Merge branch 'MDL-76284-401' of https://github.com/paulholden/moodle into MOODLE_401_...
[moodle.git] / reportbuilder / classes / datasource.php
blobd726f9985b1e0319a565693e2b11dad7f03bd711
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 declare(strict_types=1);
19 namespace core_reportbuilder;
21 use coding_exception;
22 use core_reportbuilder\local\helpers\report;
23 use core_reportbuilder\local\models\column as column_model;
24 use core_reportbuilder\local\models\filter as filter_model;
25 use core_reportbuilder\local\report\base;
26 use core_reportbuilder\local\report\column;
27 use core_reportbuilder\local\report\filter;
29 /**
30 * Class datasource
32 * @package core_reportbuilder
33 * @copyright 2021 David Matamoros <davidmc@moodle.com>
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 abstract class datasource extends base {
38 /**
39 * Return user friendly name of the datasource
41 * @return string
43 abstract public static function get_name(): string;
45 /**
46 * Add columns from the given entity name to be available to use in a custom report
48 * @param string $entityname
49 * @param array $include Include only these columns, if omitted then include all
50 * @param array $exclude Exclude these columns, if omitted then exclude none
51 * @throws coding_exception If both $include and $exclude are non-empty
53 final protected function add_columns_from_entity(string $entityname, array $include = [], array $exclude = []): void {
54 if (!empty($include) && !empty($exclude)) {
55 throw new coding_exception('Cannot specify columns to include and exclude simultaneously');
58 $entity = $this->get_entity($entityname);
60 // Retrieve filtered columns from entity, respecting given $include/$exclude parameters.
61 $columns = array_filter($entity->get_columns(), static function(column $column) use ($include, $exclude): bool {
62 if (!empty($include)) {
63 return in_array($column->get_name(), $include);
66 if (!empty($exclude)) {
67 return !in_array($column->get_name(), $exclude);
70 return true;
71 });
73 foreach ($columns as $column) {
74 $this->add_column($column);
78 /**
79 * Add default datasource columns to the report
81 * This method is optional and can be called when the report is created to add the default columns defined in the
82 * selected datasource.
84 public function add_default_columns(): void {
85 $reportid = $this->get_report_persistent()->get('id');
87 // Retrieve default column sorting, and track index of both sorted/non-sorted columns.
88 $columnidentifiers = $this->get_default_columns();
89 $defaultcolumnsorting = array_intersect_key($this->get_default_column_sorting(),
90 array_fill_keys($columnidentifiers, 1));
91 $columnnonsortingindex = count($defaultcolumnsorting) + 1;
93 foreach ($columnidentifiers as $uniqueidentifier) {
94 $column = report::add_report_column($reportid, $uniqueidentifier);
96 // After adding the column, toggle sorting according to defaults provided by the datasource.
97 $sortorder = array_search($uniqueidentifier, array_keys($defaultcolumnsorting));
98 if ($sortorder !== false) {
99 $column->set_many([
100 'sortenabled' => true,
101 'sortdirection' => $defaultcolumnsorting[$uniqueidentifier],
102 'sortorder' => $sortorder + 1,
103 ])->update();
104 } else if (!empty($defaultcolumnsorting)) {
105 $column->set('sortorder', $columnnonsortingindex++)->update();
111 * Return the columns that will be added to the report once is created
113 * @return string[]
115 abstract public function get_default_columns(): array;
118 * Return the default sorting that will be added to the report once it is created
120 * @return int[] array [column identifier => SORT_ASC/SORT_DESC]
122 public function get_default_column_sorting(): array {
123 return [];
127 * Return all configured report columns
129 * @return column[]
131 public function get_active_columns(): array {
132 $columns = [];
134 $activecolumns = column_model::get_records(['reportid' => $this->get_report_persistent()->get('id')], 'columnorder');
135 foreach ($activecolumns as $index => $column) {
136 $instance = $this->get_column($column->get('uniqueidentifier'));
137 if ($instance !== null && $instance->get_is_available()) {
138 $instance->set_persistent($column);
140 // We should clone the report column to ensure if it's added twice to a report, each operates independently.
141 $columns[] = clone $instance
142 ->set_index($index)
143 ->set_aggregation($column->get('aggregation'));
147 return $columns;
151 * Add filters from the given entity name to be available to use in a custom report
153 * @param string $entityname
154 * @param array $include Include only these filters, if omitted then include all
155 * @param array $exclude Exclude these filters, if omitted then exclude none
156 * @throws coding_exception If both $include and $exclude are non-empty
158 final protected function add_filters_from_entity(string $entityname, array $include = [], array $exclude = []): void {
159 if (!empty($include) && !empty($exclude)) {
160 throw new coding_exception('Cannot specify filters to include and exclude simultaneously');
163 $entity = $this->get_entity($entityname);
165 // Retrieve filtered filters from entity, respecting given $include/$exclude parameters.
166 $filters = array_filter($entity->get_filters(), static function(filter $filter) use ($include, $exclude): bool {
167 if (!empty($include)) {
168 return in_array($filter->get_name(), $include);
171 if (!empty($exclude)) {
172 return !in_array($filter->get_name(), $exclude);
175 return true;
178 foreach ($filters as $filter) {
179 $this->add_filter($filter);
184 * Add default datasource filters to the report
186 * This method is optional and can be called when the report is created to add the default filters defined in the
187 * selected datasource.
189 public function add_default_filters(): void {
190 $reportid = $this->get_report_persistent()->get('id');
191 $filteridentifiers = $this->get_default_filters();
192 foreach ($filteridentifiers as $uniqueidentifier) {
193 report::add_report_filter($reportid, $uniqueidentifier);
198 * Return the filters that will be added to the report once is created
200 * @return string[]
202 abstract public function get_default_filters(): array;
205 * Return all configured report filters
207 * @return filter[]
209 public function get_active_filters(): array {
210 $filters = [];
212 $activefilters = filter_model::get_filter_records($this->get_report_persistent()->get('id'), 'filterorder');
213 foreach ($activefilters as $filter) {
214 $instance = $this->get_filter($filter->get('uniqueidentifier'));
215 if ($instance !== null && $instance->get_is_available()) {
216 $filters[$instance->get_unique_identifier()] = $instance
217 ->set_persistent($filter);
221 return $filters;
225 * Add conditions from the given entity name to be available to use in a custom report
227 * @param string $entityname
228 * @param array $include Include only these conditions, if omitted then include all
229 * @param array $exclude Exclude these conditions, if omitted then exclude none
230 * @throws coding_exception If both $include and $exclude are non-empty
232 final protected function add_conditions_from_entity(string $entityname, array $include = [], array $exclude = []): void {
233 if (!empty($include) && !empty($exclude)) {
234 throw new coding_exception('Cannot specify conditions to include and exclude simultaneously');
237 $entity = $this->get_entity($entityname);
239 // Retrieve filtered conditions from entity, respecting given $include/$exclude parameters.
240 $conditions = array_filter($entity->get_conditions(), static function(filter $condition) use ($include, $exclude): bool {
241 if (!empty($include)) {
242 return in_array($condition->get_name(), $include);
245 if (!empty($exclude)) {
246 return !in_array($condition->get_name(), $exclude);
249 return true;
252 foreach ($conditions as $condition) {
253 $this->add_condition($condition);
258 * Add default datasource conditions to the report
260 * This method is optional and can be called when the report is created to add the default conditions defined in the
261 * selected datasource.
263 public function add_default_conditions(): void {
264 $reportid = $this->get_report_persistent()->get('id');
265 $conditionidentifiers = $this->get_default_conditions();
266 foreach ($conditionidentifiers as $uniqueidentifier) {
267 report::add_report_condition($reportid, $uniqueidentifier);
270 // Set the default condition values if they have been set in the datasource.
271 $this->set_condition_values($this->get_default_condition_values());
275 * Return the conditions that will be added to the report once is created
277 * @return string[]
279 abstract public function get_default_conditions(): array;
282 * Return the default condition values that will be added to the report once is created
284 * For any of the default conditions returned by the method {@see get_default_conditions} is
285 * possible to set the initial values.
287 * @return array
289 public function get_default_condition_values(): array {
290 return [];
294 * Return all configured report conditions
296 * @return filter[]
298 public function get_active_conditions(): array {
299 $conditions = [];
301 $activeconditions = filter_model::get_condition_records($this->get_report_persistent()->get('id'), 'filterorder');
302 foreach ($activeconditions as $condition) {
303 $instance = $this->get_condition($condition->get('uniqueidentifier'));
304 if ($instance !== null && $instance->get_is_available()) {
305 $conditions[$instance->get_unique_identifier()] = $instance->set_persistent($condition);
309 return $conditions;
313 * Adds all columns/filters/conditions from the given entity to the report at once
315 * @param string $entityname
317 final protected function add_all_from_entity(string $entityname): void {
318 $this->add_columns_from_entity($entityname);
319 $this->add_filters_from_entity($entityname);
320 $this->add_conditions_from_entity($entityname);
324 * Adds all columns/filters/conditions from all the entities added to the report at once
326 final protected function add_all_from_entities(): void {
327 foreach ($this->get_entities() as $entity) {
328 $this->add_all_from_entity($entity->get_entity_name());