See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [Versions 401 and 403]
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 declare(strict_types=1); 18 19 namespace core_reportbuilder; 20 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; 28 29 /** 30 * Class datasource 31 * 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 35 */ 36 abstract class datasource extends base { 37 38 /** @var float[] $elementsmodified Track the time elements of specific reports have been added, updated, removed */ 39 private static $elementsmodified = []; 40 41 /** @var array $activecolumns */ 42 private $activecolumns; 43 44 /** @var array $activefilters */ 45 private $activefilters; 46 47 /** @var array $activeconditions */ 48 private $activeconditions; 49 50 /** 51 * Return user friendly name of the datasource 52 * 53 * @return string 54 */ 55 abstract public static function get_name(): string; 56 57 /** 58 * Add columns from the given entity name to be available to use in a custom report 59 * 60 * @param string $entityname 61 * @param array $include Include only these columns, if omitted then include all 62 * @param array $exclude Exclude these columns, if omitted then exclude none 63 * @throws coding_exception If both $include and $exclude are non-empty 64 */ 65 final protected function add_columns_from_entity(string $entityname, array $include = [], array $exclude = []): void { 66 if (!empty($include) && !empty($exclude)) { 67 throw new coding_exception('Cannot specify columns to include and exclude simultaneously'); 68 } 69 70 $entity = $this->get_entity($entityname); 71 72 // Retrieve filtered columns from entity, respecting given $include/$exclude parameters. 73 $columns = array_filter($entity->get_columns(), static function(column $column) use ($include, $exclude): bool { 74 if (!empty($include)) { 75 return in_array($column->get_name(), $include); 76 } 77 78 if (!empty($exclude)) { 79 return !in_array($column->get_name(), $exclude); 80 } 81 82 return true; 83 }); 84 85 foreach ($columns as $column) { 86 $this->add_column($column); 87 } 88 } 89 90 /** 91 * Add default datasource columns to the report 92 * 93 * This method is optional and can be called when the report is created to add the default columns defined in the 94 * selected datasource. 95 */ 96 public function add_default_columns(): void { 97 $reportid = $this->get_report_persistent()->get('id'); 98 99 // Retrieve default column sorting, and track index of both sorted/non-sorted columns. 100 $columnidentifiers = $this->get_default_columns(); 101 $defaultcolumnsorting = array_intersect_key($this->get_default_column_sorting(), 102 array_fill_keys($columnidentifiers, 1)); 103 $columnnonsortingindex = count($defaultcolumnsorting) + 1; 104 105 foreach ($columnidentifiers as $uniqueidentifier) { 106 $column = report::add_report_column($reportid, $uniqueidentifier); 107 108 // After adding the column, toggle sorting according to defaults provided by the datasource. 109 $sortorder = array_search($uniqueidentifier, array_keys($defaultcolumnsorting)); 110 if ($sortorder !== false) { 111 $column->set_many([ 112 'sortenabled' => true, 113 'sortdirection' => $defaultcolumnsorting[$uniqueidentifier], 114 'sortorder' => $sortorder + 1, 115 ])->update(); 116 } else if (!empty($defaultcolumnsorting)) { 117 $column->set('sortorder', $columnnonsortingindex++)->update(); 118 } 119 } 120 } 121 122 /** 123 * Return the columns that will be added to the report once is created 124 * 125 * @return string[] 126 */ 127 abstract public function get_default_columns(): array; 128 129 /** 130 * Return the default sorting that will be added to the report once it is created 131 * 132 * @return int[] array [column identifier => SORT_ASC/SORT_DESC] 133 */ 134 public function get_default_column_sorting(): array { 135 return []; 136 } 137 138 /** 139 * Return all configured report columns 140 * 141 * @return column[] 142 */ 143 public function get_active_columns(): array { 144 $reportid = $this->get_report_persistent()->get('id'); 145 146 // Determine whether we already retrieved the columns since the report was last modified. 147 self::$elementsmodified += [$reportid => -1]; 148 if ($this->activecolumns !== null && $this->activecolumns['builttime'] > self::$elementsmodified[$reportid]) { 149 return $this->activecolumns['values']; 150 } 151 152 $this->activecolumns = ['builttime' => microtime(true), 'values' => []]; 153 154 $activecolumns = column_model::get_records(['reportid' => $reportid], 'columnorder'); 155 foreach ($activecolumns as $index => $column) { 156 $instance = $this->get_column($column->get('uniqueidentifier')); 157 158 // Ensure the column is still present and available. 159 if ($instance !== null && $instance->get_is_available()) { 160 161 // We should clone the report column to ensure if it's added twice to a report, each operates independently. 162 $this->activecolumns['values'][] = clone $instance 163 ->set_index($index) 164 ->set_persistent($column) 165 ->set_aggregation($column->get('aggregation')); 166 } 167 } 168 169 return $this->activecolumns['values']; 170 } 171 172 /** 173 * Add filters from the given entity name to be available to use in a custom report 174 * 175 * @param string $entityname 176 * @param array $include Include only these filters, if omitted then include all 177 * @param array $exclude Exclude these filters, if omitted then exclude none 178 * @throws coding_exception If both $include and $exclude are non-empty 179 */ 180 final protected function add_filters_from_entity(string $entityname, array $include = [], array $exclude = []): void { 181 if (!empty($include) && !empty($exclude)) { 182 throw new coding_exception('Cannot specify filters to include and exclude simultaneously'); 183 } 184 185 $entity = $this->get_entity($entityname); 186 187 // Retrieve filtered filters from entity, respecting given $include/$exclude parameters. 188 $filters = array_filter($entity->get_filters(), static function(filter $filter) use ($include, $exclude): bool { 189 if (!empty($include)) { 190 return in_array($filter->get_name(), $include); 191 } 192 193 if (!empty($exclude)) { 194 return !in_array($filter->get_name(), $exclude); 195 } 196 197 return true; 198 }); 199 200 foreach ($filters as $filter) { 201 $this->add_filter($filter); 202 } 203 } 204 205 /** 206 * Add default datasource filters to the report 207 * 208 * This method is optional and can be called when the report is created to add the default filters defined in the 209 * selected datasource. 210 */ 211 public function add_default_filters(): void { 212 $reportid = $this->get_report_persistent()->get('id'); 213 $filteridentifiers = $this->get_default_filters(); 214 foreach ($filteridentifiers as $uniqueidentifier) { 215 report::add_report_filter($reportid, $uniqueidentifier); 216 } 217 } 218 219 /** 220 * Return the filters that will be added to the report once is created 221 * 222 * @return string[] 223 */ 224 abstract public function get_default_filters(): array; 225 226 /** 227 * Return all configured report filters 228 * 229 * @return filter[] 230 */ 231 public function get_active_filters(): array { 232 $reportid = $this->get_report_persistent()->get('id'); 233 234 // Determine whether we already retrieved the filters since the report was last modified. 235 self::$elementsmodified += [$reportid => -1]; 236 if ($this->activefilters !== null && $this->activefilters['builttime'] > self::$elementsmodified[$reportid]) { 237 return $this->activefilters['values']; 238 } 239 240 $this->activefilters = ['builttime' => microtime(true), 'values' => []]; 241 242 $activefilters = filter_model::get_filter_records($reportid, 'filterorder'); 243 foreach ($activefilters as $filter) { 244 $instance = $this->get_filter($filter->get('uniqueidentifier')); 245 246 // Ensure the filter is still present and available. 247 if ($instance !== null && $instance->get_is_available()) { 248 $this->activefilters['values'][$instance->get_unique_identifier()] = 249 $instance->set_persistent($filter); 250 } 251 } 252 253 return $this->activefilters['values']; 254 } 255 256 /** 257 * Add conditions from the given entity name to be available to use in a custom report 258 * 259 * @param string $entityname 260 * @param array $include Include only these conditions, if omitted then include all 261 * @param array $exclude Exclude these conditions, if omitted then exclude none 262 * @throws coding_exception If both $include and $exclude are non-empty 263 */ 264 final protected function add_conditions_from_entity(string $entityname, array $include = [], array $exclude = []): void { 265 if (!empty($include) && !empty($exclude)) { 266 throw new coding_exception('Cannot specify conditions to include and exclude simultaneously'); 267 } 268 269 $entity = $this->get_entity($entityname); 270 271 // Retrieve filtered conditions from entity, respecting given $include/$exclude parameters. 272 $conditions = array_filter($entity->get_conditions(), static function(filter $condition) use ($include, $exclude): bool { 273 if (!empty($include)) { 274 return in_array($condition->get_name(), $include); 275 } 276 277 if (!empty($exclude)) { 278 return !in_array($condition->get_name(), $exclude); 279 } 280 281 return true; 282 }); 283 284 foreach ($conditions as $condition) { 285 $this->add_condition($condition); 286 } 287 } 288 289 /** 290 * Add default datasource conditions to the report 291 * 292 * This method is optional and can be called when the report is created to add the default conditions defined in the 293 * selected datasource. 294 */ 295 public function add_default_conditions(): void { 296 $reportid = $this->get_report_persistent()->get('id'); 297 $conditionidentifiers = $this->get_default_conditions(); 298 foreach ($conditionidentifiers as $uniqueidentifier) { 299 report::add_report_condition($reportid, $uniqueidentifier); 300 } 301 302 // Set the default condition values if they have been set in the datasource. 303 $this->set_condition_values($this->get_default_condition_values()); 304 } 305 306 /** 307 * Return the conditions that will be added to the report once is created 308 * 309 * @return string[] 310 */ 311 abstract public function get_default_conditions(): array; 312 313 /** 314 * Return the default condition values that will be added to the report once is created 315 * 316 * For any of the default conditions returned by the method {@see get_default_conditions} is 317 * possible to set the initial values. 318 * 319 * @return array 320 */ 321 public function get_default_condition_values(): array { 322 return []; 323 } 324 325 /** 326 * Return all configured report conditions 327 * 328 * @return filter[] 329 */ 330 public function get_active_conditions(): array { 331 $reportid = $this->get_report_persistent()->get('id'); 332 333 // Determine whether we already retrieved the conditions since the report was last modified. 334 self::$elementsmodified += [$reportid => -1]; 335 if ($this->activeconditions !== null && $this->activeconditions['builttime'] > self::$elementsmodified[$reportid]) { 336 return $this->activeconditions['values']; 337 } 338 339 $this->activeconditions = ['builttime' => microtime(true), 'values' => []]; 340 341 $activeconditions = filter_model::get_condition_records($reportid, 'filterorder'); 342 foreach ($activeconditions as $condition) { 343 $instance = $this->get_condition($condition->get('uniqueidentifier')); 344 345 // Ensure the condition is still present and available. 346 if ($instance !== null && $instance->get_is_available()) { 347 $this->activeconditions['values'][$instance->get_unique_identifier()] = 348 $instance->set_persistent($condition); 349 } 350 } 351 352 return $this->activeconditions['values']; 353 } 354 355 /** 356 * Adds all columns/filters/conditions from the given entity to the report at once 357 * 358 * @param string $entityname 359 */ 360 final protected function add_all_from_entity(string $entityname): void { 361 $this->add_columns_from_entity($entityname); 362 $this->add_filters_from_entity($entityname); 363 $this->add_conditions_from_entity($entityname); 364 } 365 366 /** 367 * Adds all columns/filters/conditions from all the entities added to the report at once 368 */ 369 final protected function add_all_from_entities(): void { 370 foreach ($this->get_entities() as $entity) { 371 $this->add_all_from_entity($entity->get_entity_name()); 372 } 373 } 374 375 /** 376 * Indicate that report elements have been modified, e.g. columns/filters/conditions have been added, removed or updated 377 * 378 * @param int $reportid 379 */ 380 final public static function report_elements_modified(int $reportid): void { 381 self::$elementsmodified[$reportid] = microtime(true); 382 } 383 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body