Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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 stdClass;
  23  use core_reportbuilder\local\models\report;
  24  use core_reportbuilder\local\report\action;
  25  use core_reportbuilder\local\report\base;
  26  use core_reportbuilder\local\report\column;
  27  
  28  /**
  29   * Base class for system reports
  30   *
  31   * @package     core_reportbuilder
  32   * @copyright   2020 Paul Holden <paulh@moodle.com>
  33   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  abstract class system_report extends base {
  36  
  37      /** @var array $parameters */
  38      private $parameters;
  39  
  40      /** @var string[] $basefields List of base fields */
  41      private $basefields = [];
  42  
  43      /** @var action[] $actions */
  44      private $actions = [];
  45  
  46      /** @var column $initialsortcolumn */
  47      private $initialsortcolumn;
  48  
  49      /** @var int $initialsortdirection */
  50      private $initialsortdirection;
  51  
  52      /**
  53       * System report constructor.
  54       *
  55       * @param report $report
  56       * @param array $parameters
  57       */
  58      final public function __construct(report $report, array $parameters) {
  59          $this->parameters = $parameters;
  60  
  61          parent::__construct($report);
  62      }
  63  
  64      /**
  65       * Validates access to view this report
  66       *
  67       * This is necessary to implement independently of the page that would typically embed the report because
  68       * subsequent pages are requested via AJAX requests, and access should be validated each time
  69       *
  70       * @return bool
  71       */
  72      abstract protected function can_view(): bool;
  73  
  74      /**
  75       * Validate access to the report
  76       *
  77       * @throws report_access_exception
  78       */
  79      final public function require_can_view(): void {
  80          if (!$this->can_view()) {
  81              throw new report_access_exception();
  82          }
  83      }
  84  
  85      /**
  86       * Report validation
  87       *
  88       * @throws report_access_exception If user cannot access the report
  89       * @throws coding_exception If no default column are specified
  90       */
  91      protected function validate(): void {
  92          parent::validate();
  93  
  94          $this->require_can_view();
  95  
  96          // Ensure the report has some default columns specified.
  97          if (empty($this->get_columns())) {
  98              throw new coding_exception('No columns added');
  99          }
 100      }
 101  
 102      /**
 103       * Add list of fields that have to be always included in SQL query for actions and row classes
 104       *
 105       * Base fields are only available in system reports because they are not compatible with aggregation
 106       *
 107       * @param string $sql SQL clause for the list of fields that only uses main table or base joins
 108       */
 109      final protected function add_base_fields(string $sql): void {
 110          $this->basefields[] = $sql;
 111      }
 112  
 113      /**
 114       * Return report base fields
 115       *
 116       * @return array
 117       */
 118      final public function get_base_fields(): array {
 119          return $this->basefields;
 120      }
 121  
 122      /**
 123       * Adds an action to the report
 124       *
 125       * @param action $action
 126       */
 127      final public function add_action(action $action): void {
 128          $this->actions[] = $action;
 129      }
 130  
 131      /**
 132       * Whether report has any actions
 133       *
 134       * @return bool
 135       */
 136      final public function has_actions(): bool {
 137          return !empty($this->actions);
 138      }
 139  
 140      /**
 141       * Return report actions
 142       *
 143       * @return action[]
 144       */
 145      final public function get_actions(): array {
 146          return $this->actions;
 147      }
 148  
 149      /**
 150       * Set all report parameters
 151       *
 152       * @param array $parameters
 153       */
 154      final public function set_parameters(array $parameters): void {
 155          $this->parameters = $parameters;
 156      }
 157  
 158      /**
 159       * Return all report parameters
 160       *
 161       * @return array
 162       */
 163      final public function get_parameters(): array {
 164          return $this->parameters;
 165      }
 166  
 167      /**
 168       * Return specific report parameter
 169       *
 170       * @param string $param
 171       * @param mixed $default
 172       * @param string $type
 173       * @return mixed
 174       */
 175      final public function get_parameter(string $param, $default, string $type) {
 176          if (!array_key_exists($param, $this->parameters)) {
 177              return $default;
 178          }
 179  
 180          return clean_param($this->parameters[$param], $type);
 181      }
 182  
 183      /**
 184       * Output the report
 185       *
 186       * @uses \core_reportbuilder\output\renderer::render_system_report()
 187       *
 188       * @return string
 189       */
 190      final public function output(): string {
 191          global $PAGE;
 192  
 193          /** @var \core_reportbuilder\output\renderer $renderer */
 194          $renderer = $PAGE->get_renderer('core_reportbuilder');
 195          $report = new \core_reportbuilder\output\system_report($this->get_report_persistent(), $this, $this->parameters);
 196  
 197          return $renderer->render($report);
 198      }
 199  
 200      /**
 201       * CSS classes to add to the row. Can be overridden by system reports do define class to be added to output according to
 202       * content of each row
 203       *
 204       * @param stdClass $row
 205       * @return string
 206       */
 207      public function get_row_class(stdClass $row): string {
 208          return '';
 209      }
 210  
 211      /**
 212       * Default 'per page' size. Can be overridden by system reports to define a different paging value
 213       *
 214       * @return int
 215       */
 216      public function get_default_per_page(): int {
 217          return self::DEFAULT_PAGESIZE;
 218      }
 219  
 220      /**
 221       * Called before rendering each row. Can be overridden to pre-fetch/create objects and store them in the class, which can
 222       * later be used in column and action callbacks
 223       *
 224       * @param stdClass $row
 225       */
 226      public function row_callback(stdClass $row): void {
 227          return;
 228      }
 229  
 230      /**
 231       * Validates access to download this report.
 232       *
 233       * @return bool
 234       */
 235      final public function can_be_downloaded(): bool {
 236          return $this->can_view() && $this->is_downloadable();
 237      }
 238  
 239      /**
 240       * Return list of column names that will be excluded when table is downloaded. Extending classes should override this method
 241       * as appropriate
 242       *
 243       * @return string[] Array of column unique identifiers
 244       */
 245      public function get_exclude_columns_for_download(): array {
 246          return [];
 247      }
 248  
 249      /**
 250       * Set initial sort column and sort direction for the report
 251       *
 252       * @param string $uniqueidentifier
 253       * @param int $sortdirection One of SORT_ASC or SORT_DESC
 254       * @throws coding_exception
 255       */
 256      public function set_initial_sort_column(string $uniqueidentifier, int $sortdirection): void {
 257          if (!$sortcolumn = $this->get_column($uniqueidentifier)) {
 258              throw new coding_exception('Unknown column identifier', $uniqueidentifier);
 259          }
 260  
 261          $this->initialsortcolumn = $sortcolumn;
 262          $this->initialsortdirection = $sortdirection;
 263      }
 264  
 265      /**
 266       * Get initial sort column
 267       *
 268       * @return column|null
 269       */
 270      public function get_initial_sort_column(): ?column {
 271          return $this->initialsortcolumn;
 272      }
 273  
 274      /**
 275       * Get initial sort column direction
 276       *
 277       * @return int
 278       */
 279      public function get_initial_sort_direction(): int {
 280          return $this->initialsortdirection;
 281      }
 282  }