Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?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;
use invalid_parameter_exception;
use core\persistent;
use core_reportbuilder\datasource;
use core_reportbuilder\manager;
use core_reportbuilder\local\models\column;
use core_reportbuilder\local\models\filter;
use core_reportbuilder\local\models\report as report_model;

/**
 * Helper class for manipulating custom reports and their elements (columns, filters, conditions, etc)
 *
 * @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 {

    /**
     * Create custom report
     *
     * @param stdClass $data
     * @param bool $default If $default is set to true it will populate report with default layout as defined by the selected
     *                      source. These include pre-defined columns, filters and conditions.
     * @return report_model
     */
    public static function create_report(stdClass $data, bool $default = true): report_model {
        $data->name = trim($data->name);
        $data->type = datasource::TYPE_CUSTOM_REPORT;

        $reportpersistent = manager::create_report_persistent($data);

        // Add datasource default columns, filters and conditions to the report.
        if ($default) {
            $source = $reportpersistent->get('source');
            /** @var datasource $datasource */
            $datasource = new $source($reportpersistent, []);
            $datasource->add_default_columns();
            $datasource->add_default_filters();
            $datasource->add_default_conditions();
        }

        return $reportpersistent;
    }

    /**
     * Update custom report
     *
     * @param stdClass $data
     * @return report_model
     */
    public static function update_report(stdClass $data): report_model {
        $report = report_model::get_record(['id' => $data->id, 'type' => datasource::TYPE_CUSTOM_REPORT]);
        if ($report === false) {
            throw new invalid_parameter_exception('Invalid report');
        }

        $report->set_many([
            'name' => trim($data->name),
            'uniquerows' => $data->uniquerows,
        ])->update();

        return $report;
    }

    /**
     * Delete custom report
     *
     * @param int $reportid
     * @return bool
     * @throws invalid_parameter_exception
     */
    public static function delete_report(int $reportid): bool {
        $report = report_model::get_record(['id' => $reportid, 'type' => datasource::TYPE_CUSTOM_REPORT]);
        if ($report === false) {
            throw new invalid_parameter_exception('Invalid report');
        }

        return $report->delete();
    }

    /**
     * Add given column to report
     *
     * @param int $reportid
     * @param string $uniqueidentifier
     * @return column
     * @throws invalid_parameter_exception
     */
    public static function add_report_column(int $reportid, string $uniqueidentifier): column {
        $report = manager::get_report_from_id($reportid);

> // Ensure column is available.
if (!array_key_exists($uniqueidentifier, $report->get_columns())) { throw new invalid_parameter_exception('Invalid column'); } $column = new column(0, (object) [ 'reportid' => $reportid, 'uniqueidentifier' => $uniqueidentifier, 'columnorder' => column::get_max_columnorder($reportid, 'columnorder') + 1, 'sortorder' => column::get_max_columnorder($reportid, 'sortorder') + 1, ]); return $column->create(); } /** * Delete given column from report * * @param int $reportid * @param int $columnid * @return bool * @throws invalid_parameter_exception */ public static function delete_report_column(int $reportid, int $columnid): bool { global $DB; $column = column::get_record(['id' => $columnid, 'reportid' => $reportid]); if ($column === false) { throw new invalid_parameter_exception('Invalid column'); } // After deletion, re-index remaining report columns. if ($result = $column->delete()) { $sqlupdateorder = ' UPDATE {' . column::TABLE . '} SET columnorder = columnorder - 1 WHERE reportid = :reportid AND columnorder > :columnorder'; $DB->execute($sqlupdateorder, ['reportid' => $reportid, 'columnorder' => $column->get('columnorder')]); } return $result; } /** * Re-order given column within a report * * @param int $reportid * @param int $columnid * @param int $position * @return bool * @throws invalid_parameter_exception */ public static function reorder_report_column(int $reportid, int $columnid, int $position): bool { $column = column::get_record(['id' => $columnid, 'reportid' => $reportid]); if ($column === false) { throw new invalid_parameter_exception('Invalid column'); } // Get the rest of the report columns, excluding the one we are moving. $columns = column::get_records_select('reportid = :reportid AND id <> :id', [ 'reportid' => $reportid, 'id' => $columnid, ], 'columnorder'); return static::reorder_persistents_by_field($column, $columns, $position, 'columnorder'); } /** * Re-order given column sorting within a report * * @param int $reportid * @param int $columnid * @param int $position * @return bool * @throws invalid_parameter_exception */ public static function reorder_report_column_sorting(int $reportid, int $columnid, int $position): bool { $column = column::get_record(['id' => $columnid, 'reportid' => $reportid]); if ($column === false) { throw new invalid_parameter_exception('Invalid column'); } // Get the rest of the report columns, excluding the one we are moving. $columns = column::get_records_select('reportid = :reportid AND id <> :id', [ 'reportid' => $reportid, 'id' => $columnid, ], 'sortorder'); return static::reorder_persistents_by_field($column, $columns, $position, 'sortorder'); } /** * Toggle sorting options for given column within a report * * @param int $reportid * @param int $columnid * @param bool $enabled * @param int $direction * @return bool * @throws invalid_parameter_exception */ public static function toggle_report_column_sorting(int $reportid, int $columnid, bool $enabled, int $direction = SORT_ASC): bool { $column = column::get_record(['id' => $columnid, 'reportid' => $reportid]); if ($column === false) { throw new invalid_parameter_exception('Invalid column'); } return $column->set_many([ 'sortenabled' => $enabled, 'sortdirection' => $direction, ])->update(); } /** * Add given condition to report * * @param int $reportid * @param string $uniqueidentifier * @return filter * @throws invalid_parameter_exception */ public static function add_report_condition(int $reportid, string $uniqueidentifier): filter { $report = manager::get_report_from_id($reportid);
> // Ensure condition is available.
if (!array_key_exists($uniqueidentifier, $report->get_conditions())) { throw new invalid_parameter_exception('Invalid condition'); }
> // Ensure condition wasn't already added. $condition = new filter(0, (object) [ > if (array_key_exists($uniqueidentifier, $report->get_active_conditions())) { 'reportid' => $reportid, > throw new invalid_parameter_exception('Duplicate condition'); 'uniqueidentifier' => $uniqueidentifier, > } 'iscondition' => true, >
'filterorder' => filter::get_max_filterorder($reportid, true) + 1, ]); return $condition->create(); } /** * Delete given condition from report * * @param int $reportid * @param int $conditionid * @return bool * @throws invalid_parameter_exception */ public static function delete_report_condition(int $reportid, int $conditionid): bool { global $DB; $condition = filter::get_condition_record($reportid, $conditionid); if ($condition === false) { throw new invalid_parameter_exception('Invalid condition'); } // After deletion, re-index remaining report conditions. if ($result = $condition->delete()) { $sqlupdateorder = ' UPDATE {' . filter::TABLE . '} SET filterorder = filterorder - 1 WHERE reportid = :reportid AND filterorder > :filterorder AND iscondition = 1'; $DB->execute($sqlupdateorder, ['reportid' => $reportid, 'filterorder' => $condition->get('filterorder')]); } return $result; } /** * Re-order given condition within a report * * @param int $reportid * @param int $conditionid * @param int $position * @return bool * @throws invalid_parameter_exception */ public static function reorder_report_condition(int $reportid, int $conditionid, int $position): bool { $condition = filter::get_condition_record($reportid, $conditionid); if ($condition === false) { throw new invalid_parameter_exception('Invalid condition'); } // Get the rest of the report conditions, excluding the one we are moving. $conditions = filter::get_records_select('reportid = :reportid AND iscondition = 1 AND id <> :id', [ 'reportid' => $reportid, 'id' => $conditionid, ], 'filterorder'); return static::reorder_persistents_by_field($condition, $conditions, $position, 'filterorder'); } /** * Add given filter to report * * @param int $reportid * @param string $uniqueidentifier * @return filter * @throws invalid_parameter_exception */ public static function add_report_filter(int $reportid, string $uniqueidentifier): filter { $report = manager::get_report_from_id($reportid);
< $reportfilters = $report->get_filters(); < if (!array_key_exists($uniqueidentifier, $reportfilters)) {
> // Ensure filter is available. > if (!array_key_exists($uniqueidentifier, $report->get_filters())) {
throw new invalid_parameter_exception('Invalid filter');
> } } > > // Ensure filter wasn't already added. $filter = new filter(0, (object) [ > if (array_key_exists($uniqueidentifier, $report->get_active_filters())) { 'reportid' => $reportid, > throw new invalid_parameter_exception('Duplicate filter');
'uniqueidentifier' => $uniqueidentifier, 'filterorder' => filter::get_max_filterorder($reportid) + 1, ]); return $filter->create(); } /** * Delete given filter from report * * @param int $reportid * @param int $filterid * @return bool * @throws invalid_parameter_exception */ public static function delete_report_filter(int $reportid, int $filterid): bool { global $DB; $filter = filter::get_filter_record($reportid, $filterid); if ($filter === false) { throw new invalid_parameter_exception('Invalid filter'); } // After deletion, re-index remaining report filters. if ($result = $filter->delete()) { $sqlupdateorder = ' UPDATE {' . filter::TABLE . '} SET filterorder = filterorder - 1 WHERE reportid = :reportid AND filterorder > :filterorder AND iscondition = 0'; $DB->execute($sqlupdateorder, ['reportid' => $reportid, 'filterorder' => $filter->get('filterorder')]); } return $result; } /** * Re-order given filter within a report * * @param int $reportid * @param int $filterid * @param int $position * @return bool * @throws invalid_parameter_exception */ public static function reorder_report_filter(int $reportid, int $filterid, int $position): bool { $filter = filter::get_filter_record($reportid, $filterid); if ($filter === false) { throw new invalid_parameter_exception('Invalid filter'); } // Get the rest of the report filters, excluding the one we are moving. $filters = filter::get_records_select('reportid = :reportid AND iscondition = 0 AND id <> :id', [ 'reportid' => $reportid, 'id' => $filterid, ], 'filterorder'); return static::reorder_persistents_by_field($filter, $filters, $position, 'filterorder'); } /** * Get available columns for a given report * * @param report_model $persistent * @return array * * @deprecated since Moodle 4.1 - please do not use this function any more, {@see custom_report_column_cards_exporter} */ public static function get_available_columns(report_model $persistent) : array { debugging('The function ' . __FUNCTION__ . '() is deprecated, please do not use it any more. ' . 'See \'custom_report_column_cards_exporter\' class for replacement', DEBUG_DEVELOPER); $available = []; $report = manager::get_report_from_persistent($persistent); // Get current report columns. foreach ($report->get_columns() as $column) { $entityname = $column->get_entity_name(); $entitytitle = $column->get_title(); if (!array_key_exists($entityname, $available)) { $available[$entityname] = [ 'name' => (string) $report->get_entity_title($entityname), 'key' => $entityname, 'items' => [], ]; } $available[$entityname]['items'][] = [ 'name' => $entitytitle, 'identifier' => $column->get_unique_identifier(), 'title' => get_string('addcolumn', 'core_reportbuilder', $entitytitle), 'action' => 'report-add-column' ]; } return array_values($available); } /** * Helper method for re-ordering given persistents (columns, filters, etc) * * @param persistent $persistent The persistent we are moving * @param persistent[] $persistents The rest of the persistents * @param int $position * @param string $field The field we need to update * @return bool */ private static function reorder_persistents_by_field(persistent $persistent, array $persistents, int $position, string $field): bool { // Splice into new position. array_splice($persistents, $position - 1, 0, [$persistent]); $fieldorder = 1; foreach ($persistents as $persistent) { $persistent->set($field, $fieldorder++) ->update(); } return true; } }