MDL-70794 reportbuilder: management and further utility classes.

We define the base classes and APIs for reports, that can contain
columns and filters instances themselves.
This commit is contained in:
Paul Holden 2020-12-09 14:23:10 +00:00
parent 2a20238924
commit 93025be2e7
10 changed files with 1198 additions and 0 deletions

View file

@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\local\helpers;
use stdClass;
/**
* Class containing helper methods for format columns data as callbacks.
*
* @package core_reportbuilder
* @copyright 2021 Sara Arjona <sara@moodle.com> based on Alberto Lara Hernández <albertolara@moodle.com> code.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format {
/**
* Returns formatted date.
*
* @param int $value Unix timestamp
* @param stdClass $row
* @param string|null $format Format string for strftime
* @return string
*/
public static function userdate(int $value, stdClass $row, ?string $format = null): string {
return $value ? userdate($value, $format) : '';
}
/**
* Returns yes/no string depending on the given value
*
* @param bool $value
* @return string
*/
public static function boolean_as_text(bool $value): string {
return $value ? get_string('yes') : get_string('no');
}
}

View file

@ -0,0 +1,101 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\local\models;
use context;
use context_system;
use core\persistent;
use core_reportbuilder\local\report\base;
/**
* Persistent class to represent a report
*
* @package core_reportbuilder
* @copyright 2018 Alberto Lara Hernández <albertolara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class report extends persistent {
/** @var string The table name. */
public const TABLE = 'reportbuilder_report';
/**
* Return the definition of the properties of this model
*
* @return array
*/
protected static function define_properties(): array {
return [
'source' => [
'type' => PARAM_RAW,
],
'type' => [
'type' => PARAM_INT,
'choices' => [
base::TYPE_CUSTOM_REPORT,
base::TYPE_SYSTEM_REPORT,
],
],
'contextid' => [
'type' => PARAM_INT,
'default' => static function(): int {
return context_system::instance()->id;
}
],
'component' => [
'type' => PARAM_COMPONENT,
'default' => '',
],
'area' => [
'type' => PARAM_AREA,
'default' => '',
],
'itemid' => [
'type' => PARAM_INT,
'default' => 0,
],
'usercreated' => [
'type' => PARAM_INT,
'default' => static function(): int {
global $USER;
return (int) $USER->id;
},
],
];
}
/**
* Return report ID
*
* @return int
*/
protected function get_id(): int {
return (int) $this->raw_get('id');
}
/**
* Return report context, used by exporters
*
* @return context
*/
public function get_context(): context {
return context::instance_by_id($this->raw_get('contextid'));
}
}

View file

@ -0,0 +1,420 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\local\report;
use coding_exception;
use context;
use lang_string;
use core_reportbuilder\local\filters\base as filter_base;
use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\helpers\user_filter_manager;
use core_reportbuilder\local\models\report;
/**
* Base class for all reports
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class base {
/** @var int Custom report type value */
public const TYPE_CUSTOM_REPORT = 0;
/** @var int System report type value */
public const TYPE_SYSTEM_REPORT = 1;
/** @var int Default paging limit */
public const DEFAULT_PAGESIZE = 30;
/** @var report $report Report persistent */
private $report;
/** @var string $maintable */
private $maintable = '';
/** @var string $maintablealias */
private $maintablealias = '';
/** @var array $sqljoins */
private $sqljoins = [];
/** @var array $sqlwheres */
private $sqlwheres = [];
/** @var array $sqlparams */
private $sqlparams = [];
/** @var lang_string[] */
private $entitytitles = [];
/** @var column[] $columns */
private $columns = [];
/** @var filter[] $filters */
private $filters = [];
/** @var bool $downloadable Set if the report can be downloaded */
private $downloadable = false;
/** @var string $downloadfilename Name of the downloaded file */
private $downloadfilename = '';
/**
* Base report constructor
*
* @param report $report
*/
public function __construct(report $report) {
$this->report = $report;
// Initialise and validate the report.
$this->initialise();
$this->validate();
}
/**
* Returns persistent class used when initialising this report
*
* @return report
*/
final public function get_report_persistent(): report {
return $this->report;
}
/**
* Initialise report. Specify which columns, filters, etc should be present
*
* To set the base query use:
* - {@see set_main_table}
* - {@see add_base_condition_simple} or {@see add_base_condition_sql}
* - {@see add_join}
*
* To add content to the report use:
* - {@see add_entity}
* - {@see add_column}
* - {@see add_filter}
* - etc
*/
abstract protected function initialise(): void;
/**
* Get the report availability. Sub-classes should override this method to declare themselves unavailable, for example if
* they require classes that aren't present due to missing plugin
*
* @return bool
*/
public static function is_available(): bool {
return true;
}
/**
* Perform some basic validation about expected class properties
*
* @throws coding_exception
*/
protected function validate(): void {
if (empty($this->maintable)) {
throw new coding_exception('Report must define main table by calling $this->set_main_table()');
}
if (empty($this->columns)) {
throw new coding_exception('Report must define at least one column by calling $this->add_column()');
}
}
/**
* Set the main table and alias for the SQL query
*
* @param string $tablename
* @param string $tablealias
*/
final public function set_main_table(string $tablename, string $tablealias = ''): void {
$this->maintable = $tablename;
$this->maintablealias = $tablealias;
}
/**
* Get the main table name
*
* @return string
*/
final public function get_main_table(): string {
return $this->maintable;
}
/**
* Get the alias for the main table
*
* @return string
*/
final public function get_main_table_alias(): string {
return $this->maintablealias;
}
/**
* Adds report JOIN clause that is always added
*
* @param string $join
* @param array $params
* @param bool $validateparams Some queries might add non-standard params and validation could fail
*/
protected function add_join(string $join, array $params = [], bool $validateparams = true): void {
if ($validateparams) {
database::validate_params($params);
}
$this->sqljoins[trim($join)] = trim($join);
$this->sqlparams += $params;
}
/**
* Return report JOIN clauses
*
* @return array
*/
public function get_joins(): array {
return array_values($this->sqljoins);
}
/**
* Define simple "field = value" clause to apply to the report query
*
* @param string $fieldname
* @param mixed $fieldvalue
*/
final public function add_base_condition_simple(string $fieldname, $fieldvalue): void {
if ($fieldvalue === null) {
$this->add_base_condition_sql("{$fieldname} IS NULL");
} else {
$fieldvalueparam = database::generate_param_name();
$this->add_base_condition_sql("{$fieldname} = :{$fieldvalueparam}", [
$fieldvalueparam => $fieldvalue,
]);
}
}
/**
* Define more complex clause that will always be applied to the report query
*
* @param string $where
* @param array $params Note that the param names should be generated by {@see database::generate_param_name}
*/
final public function add_base_condition_sql(string $where, array $params = []): void {
database::validate_params($params);
$this->sqlwheres[] = trim($where);
$this->sqlparams = $params + $this->sqlparams;
}
/**
* Return base select/params for the report query
*
* @return array [string $select, array $params]
*/
final public function get_base_condition(): array {
return [
implode(' AND ', $this->sqlwheres),
$this->sqlparams,
];
}
/**
* Define a new entity for the report
*
* @param string $name
* @param lang_string $title
* @throws coding_exception
*/
final protected function annotate_entity(string $name, lang_string $title): void {
if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
throw new coding_exception('Entity name must be comprised of alphanumeric character, underscore or dash');
}
$this->entitytitles[$name] = $title;
}
/**
* Adds a column to the report
*
* @param column $column
* @return column
* @throws coding_exception
*/
final protected function add_column(column $column): column {
if (!array_key_exists($column->get_entity_name(), $this->entitytitles)) {
throw new coding_exception('Invalid entity name', $column->get_entity_name());
}
$name = $column->get_name();
if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
throw new coding_exception('Column name must be comprised of alphanumeric character, underscore or dash');
}
$uniqueidentifier = $column->get_unique_identifier();
if (array_key_exists($uniqueidentifier, $this->columns)) {
throw new coding_exception('Duplicate column identifier', $uniqueidentifier);
}
$this->columns[$uniqueidentifier] = $column;
return $column;
}
/**
* Return report column by unique identifier
*
* @param string $uniqueidentifier
* @return column|null
*/
final public function get_column(string $uniqueidentifier): ?column {
return $this->columns[$uniqueidentifier] ?? null;
}
/**
* Return all available report columns
*
* @return column[]
*/
final public function get_columns(): array {
return array_filter($this->columns, static function(column $column): bool {
return $column->get_is_available();
});
}
/**
* Adds a filter to the report
*
* @param filter $filter
* @return filter
* @throws coding_exception
*/
final protected function add_filter(filter $filter): filter {
if (!array_key_exists($filter->get_entity_name(), $this->entitytitles)) {
throw new coding_exception('Invalid entity name', $filter->get_entity_name());
}
$name = $filter->get_name();
if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
throw new coding_exception('Filter name must be comprised of alphanumeric character, underscore or dash');
}
$uniqueidentifier = $filter->get_unique_identifier();
if (array_key_exists($uniqueidentifier, $this->filters)) {
throw new coding_exception('Duplicate filter identifier', $uniqueidentifier);
}
$this->filters[$uniqueidentifier] = $filter;
return $filter;
}
/**
* Return report filter by unique identifier
*
* @param string $uniqueidentifier
* @return filter|null
*/
final public function get_filter(string $uniqueidentifier): ?filter {
return $this->filters[$uniqueidentifier] ?? null;
}
/**
* Return all available report filters
*
* @return filter[]
*/
final public function get_filters(): array {
return array_filter($this->filters, static function(filter $filter): bool {
return $filter->get_is_available();
});
}
/**
* Return all report filter instances
*
* @return filter_base[]
*/
final public function get_filter_instances(): array {
return array_map(static function(filter $filter): filter_base {
/** @var filter_base $filterclass */
$filterclass = $filter->get_filter_class();
return $filterclass::create($filter);
}, $this->get_filters());
}
/**
* Set the filter values of the report
*
* @param array $values
* @return bool
*/
final public function set_filter_values(array $values): bool {
return user_filter_manager::set($this->report->get('id'), $values);
}
/**
* Get the filter values of the report
*
* @return array
*/
final public function get_filter_values(): array {
return user_filter_manager::get($this->report->get('id'));
}
/**
* Set if the report can be downloaded.
*
* @param bool $downloadable
* @param string $downloadfilename If the report is downloadable, then a filename should be provided here
*/
final public function set_downloadable(bool $downloadable, string $downloadfilename = 'export'): void {
$this->downloadable = $downloadable;
$this->downloadfilename = $downloadfilename;
}
/**
* Get if the report can be downloaded.
*
* @return bool
*/
final public function is_downloadable(): bool {
return $this->downloadable;
}
/**
* Return the downloadable report filename
*
* @return string
*/
final public function get_downloadfilename(): string {
return $this->downloadfilename;
}
/**
* Returns the report context
*
* @return context
*/
public function get_context(): context {
return $this->report->get_context();
}
}

View file

@ -0,0 +1,87 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use stdClass;
use core_reportbuilder\local\models\report;
use core_reportbuilder\local\report\base;
/**
* Report management class
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class manager {
/**
* Return an instance of a report class from the given report persistent
*
* @param report $report
* @param array $parameters
* @return base
* @throws source_invalid_exception
* @throws source_unavailable_exception
*/
public static function get_report_from_persistent(report $report, array $parameters = []): base {
$source = $report->get('source');
// Throw exception for invalid or unavailable report source.
if (!self::report_source_exists($source)) {
throw new source_invalid_exception($source);
} else if (!self::report_source_available($source)) {
throw new source_unavailable_exception($source);
}
return new $source($report, $parameters);
}
/**
* Verify that report source exists and extends appropriate base classes
*
* @param string $source Full namespaced path to report definition
* @param string $additionalbaseclass Specify addition base class that given classname should extend
* @return bool
*/
public static function report_source_exists(string $source, string $additionalbaseclass = ''): bool {
return (class_exists($source) && is_subclass_of($source, base::class) &&
(empty($additionalbaseclass) || is_subclass_of($source, $additionalbaseclass)));
}
/**
* Verify given report source is available. Note that it is assumed caller has already checked that it exists
*
* @param string $source
* @return bool
*/
public static function report_source_available(string $source): bool {
return call_user_func([$source, 'is_available']);
}
/**
* Create new report persistent
*
* @param stdClass $reportdata
* @return report
*/
public static function create_report_persistent(stdClass $reportdata): report {
return (new report(0, $reportdata))->create();
}
}

View file

@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use moodle_exception;
/**
* User cannot access report exception
*
* @package core_reportbuilder
* @copyright 2021 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class report_access_exception extends moodle_exception {
/**
* Constructor
*/
public function __construct() {
parent::__construct('errorreportaccess', 'reportbuilder');
}
}

View file

@ -0,0 +1,40 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use moodle_exception;
/**
* Invalid report source exception
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class source_invalid_exception extends moodle_exception {
/**
* Constructor
*
* @param string $source
*/
public function __construct(string $source) {
parent::__construct('errorsourceinvalid', 'reportbuilder', '', null, $source);
}
}

View file

@ -0,0 +1,40 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use moodle_exception;
/**
* Unavailable report source exception
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class source_unavailable_exception extends moodle_exception {
/**
* Constructor
*
* @param string $source
*/
public function __construct(string $source) {
parent::__construct('errorsourceunavailable', 'reportbuilder', '', null, $source);
}
}

View file

@ -0,0 +1,265 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use coding_exception;
use stdClass;
use core_reportbuilder\local\models\report;
use core_reportbuilder\local\report\action;
use core_reportbuilder\local\report\base;
use core_reportbuilder\local\report\column;
/**
* Base class for system reports
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class system_report extends base {
/** @var array $parameters */
private $parameters;
/** @var string[] $basefields List of base fields */
private $basefields = [];
/** @var action[] $actions */
private $actions = [];
/** @var column $initialsortcolumn */
private $initialsortcolumn;
/** @var int $initialsortdirection */
private $initialsortdirection;
/**
* System report constructor.
*
* @param report $report
* @param array $parameters
*/
final public function __construct(report $report, array $parameters) {
$this->parameters = $parameters;
parent::__construct($report);
}
/**
* Validates access to view this report
*
* This is necessary to implement independently of the page that would typically embed the report because
* subsequent pages are requested via AJAX requests, and access should be validated each time
*
* @return bool
*/
abstract protected function can_view(): bool;
/**
* Validate access to the report
*
* @throws report_access_exception
*/
final public function require_can_view(): void {
if (!$this->can_view()) {
throw new report_access_exception();
}
}
/**
* Report validation
*
* @throws report_access_exception If user cannot access the report
* @throws coding_exception If no default column are specified
*/
protected function validate(): void {
parent::validate();
$this->require_can_view();
// Ensure the report has some default columns specified.
if (empty($this->get_columns())) {
throw new coding_exception('No columns added');
}
}
/**
* Add list of fields that have to be always included in SQL query for actions and row classes
*
* Base fields are only available in system reports because they are not compatible with aggregation
*
* @param string $sql SQL clause for the list of fields that only uses main table or base joins
*/
final protected function add_base_fields(string $sql): void {
$this->basefields[] = $sql;
}
/**
* Return report base fields
*
* @return array
*/
final public function get_base_fields(): array {
return $this->basefields;
}
/**
* Adds an action to the report
*
* @param action $action
*/
final public function add_action(action $action): void {
$this->actions[] = $action;
}
/**
* Whether report has any actions
*
* @return bool
*/
final public function has_actions(): bool {
return !empty($this->actions);
}
/**
* Return report actions
*
* @return action[]
*/
final public function get_actions(): array {
return $this->actions;
}
/**
* Set all report parameters
*
* @param array $parameters
*/
final public function set_parameters(array $parameters): void {
$this->parameters = $parameters;
}
/**
* Return all report parameters
*
* @return array
*/
final public function get_parameters(): array {
return $this->parameters;
}
/**
* Return specific report parameter
*
* @param string $param
* @param mixed $default
* @param string $type
* @return mixed
*/
final public function get_parameter(string $param, $default, string $type) {
if (!array_key_exists($param, $this->parameters)) {
return $default;
}
return clean_param($this->parameters[$param], $type);
}
/**
* CSS classes to add to the row. Can be overridden by system reports do define class to be added to output according to
* content of each row
*
* @param stdClass $row
* @return string
*/
public function get_row_class(stdClass $row): string {
return '';
}
/**
* Default 'per page' size. Can be overridden by system reports to define a different paging value
*
* @return int
*/
public function get_default_per_page(): int {
return self::DEFAULT_PAGESIZE;
}
/**
* Called before rendering each row. Can be overridden to pre-fetch/create objects and store them in the class, which can
* later be used in column and action callbacks
*
* @param stdClass $row
*/
public function row_callback(stdClass $row): void {
return;
}
/**
* Validates access to download this report.
*
* @return bool
*/
final public function can_be_downloaded(): bool {
return $this->can_view() && $this->is_downloadable();
}
/**
* Return list of column names that will be excluded when table is downloaded. Extending classes should override this method
* as appropriate
*
* @return string[] Array of column unique identifiers
*/
public function get_exclude_columns_for_download(): array {
return [];
}
/**
* Set initial sort column and sort direction for the report
*
* @param string $uniqueidentifier
* @param int $sortdirection One of SORT_ASC or SORT_DESC
* @throws coding_exception
*/
public function set_initial_sort_column(string $uniqueidentifier, int $sortdirection): void {
if (!$sortcolumn = $this->get_column($uniqueidentifier)) {
throw new coding_exception('Unknown column identifier', $uniqueidentifier);
}
$this->initialsortcolumn = $sortcolumn;
$this->initialsortdirection = $sortdirection;
}
/**
* Get initial sort column
*
* @return column|null
*/
public function get_initial_sort_column(): ?column {
return $this->initialsortcolumn;
}
/**
* Get initial sort column direction
*
* @return int
*/
public function get_initial_sort_direction(): int {
return $this->initialsortdirection;
}
}

View file

@ -0,0 +1,87 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder;
use context;
use core_reportbuilder\local\models\report;
use core_reportbuilder\local\report\base;
/**
* Factory class for creating system report instances
*
* @package core_reportbuilder
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class system_report_factory {
/**
* Create and return instance of given system report source
*
* @param string $source Class path of system report definition
* @param context $context
* @param string $component
* @param string $area
* @param int $itemid
* @param array $parameters Simple key/value pairs, accessed inside reports using $this->get_parameter()
* @return system_report
* @throws source_invalid_exception
*/
public static function create(string $source, context $context, string $component = '', string $area = '',
int $itemid = 0, array $parameters = []): system_report {
// Exit early if source isn't a system report.
if (!manager::report_source_exists($source, system_report::class)) {
throw new source_invalid_exception($source);
}
$report = static::get_report_persistent($source, $context, $component, $area, $itemid);
return manager::get_report_from_persistent($report, $parameters);
}
/**
* Given a report source, with accompanying context information, return a persistent report instance
*
* @param string $source
* @param context $context
* @param string $component
* @param string $area
* @param int $itemid
* @return report
*/
private static function get_report_persistent(string $source, context $context, string $component = '', string $area = '',
int $itemid = 0): report {
$reportdata = [
'type' => base::TYPE_SYSTEM_REPORT,
'source' => $source,
'contextid' => $context->id,
'component' => $component,
'area' => $area,
'itemid' => $itemid,
];
if ($report = report::get_record($reportdata)) {
return $report;
}
return manager::create_report_persistent((object) $reportdata);
}
}

View file

@ -0,0 +1,67 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\local\helpers;
use advanced_testcase;
use stdClass;
/**
* Unit tests for the format helper
*
* @package core_reportbuilder
* @covers \core_reportbuilder\local\helpers\format
* @copyright 2021 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class format_testcase extends advanced_testcase {
/**
* Test userdate method
*/
public function test_userdate(): void {
$now = time();
$userdate = format::userdate($now, new stdClass());
$this->assertEquals(userdate($now), $userdate);
}
/**
* Data provider for {@see test_boolean_as_text}
*
* @return array
*/
public function boolean_as_text_provider(): array {
return [
[false, get_string('no')],
[true, get_string('yes')],
];
}
/**
* Test boolean as text
*
* @param bool $value
* @param string $expected
*
* @dataProvider boolean_as_text_provider
*/
public function test_boolean_as_text(bool $value, string $expected): void {
$this->assertEquals($expected, format::boolean_as_text($value));
}
}