mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
MDL-74364 course: Add course participants datasource
- New Report Builder source for course participants - New course completion entity - New course enrolment entity - New course last access entity
This commit is contained in:
parent
896e126a66
commit
0a66ba0188
148
course/classes/reportbuilder/datasource/participants.php
Normal file
148
course/classes/reportbuilder/datasource/participants.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?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_course\reportbuilder\datasource;
|
||||
|
||||
use core_course\local\entities\course_category;
|
||||
use core_course\reportbuilder\local\entities\access;
|
||||
use core_course\reportbuilder\local\entities\completion;
|
||||
use core_course\reportbuilder\local\entities\enrolment;
|
||||
use core_reportbuilder\datasource;
|
||||
use core_reportbuilder\local\entities\course;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
|
||||
/**
|
||||
* Course participants datasource
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class participants extends datasource {
|
||||
|
||||
/**
|
||||
* Initialise report
|
||||
*/
|
||||
protected function initialise(): void {
|
||||
$courseentity = new course();
|
||||
$course = $courseentity->get_table_alias('course');
|
||||
$this->add_entity($courseentity);
|
||||
|
||||
$this->set_main_table('course', $course);
|
||||
|
||||
// Exclude site course.
|
||||
$paramsiteid = database::generate_param_name();
|
||||
$this->add_base_condition_sql("{$course}.id != :{$paramsiteid}", [$paramsiteid => SITEID]);
|
||||
|
||||
// Join the course category entity.
|
||||
$coursecatentity = new course_category();
|
||||
$categories = $coursecatentity->get_table_alias('course_categories');
|
||||
$this->add_entity($coursecatentity
|
||||
->add_join("JOIN {course_categories} {$categories} ON {$categories}.id = {$course}.category"));
|
||||
|
||||
// Join the enrolments entity.
|
||||
$enrolmententity = new enrolment();
|
||||
$userenrolment = $enrolmententity->get_table_alias('user_enrolments');
|
||||
$enrol = $enrolmententity->get_table_alias('enrol');
|
||||
$enroljoin = "LEFT JOIN {enrol} {$enrol} ON {$enrol}.courseid = {$course}.id";
|
||||
$userenrolmentjoin = " LEFT JOIN {user_enrolments} {$userenrolment} ON {$userenrolment}.enrolid = {$enrol}.id";
|
||||
$enrolmententity->add_joins([$enroljoin, $userenrolmentjoin]);
|
||||
$this->add_entity($enrolmententity);
|
||||
|
||||
// Join user entity.
|
||||
$userentity = new user();
|
||||
$user = $userentity->get_table_alias('user');
|
||||
$userentity->add_joins($enrolmententity->get_joins());
|
||||
$userentity->add_join("LEFT JOIN {user} {$user} ON {$userenrolment}.userid = {$user}.id");
|
||||
$this->add_entity($userentity);
|
||||
|
||||
// Join completion entity.
|
||||
$completionentity = new completion();
|
||||
$completion = $completionentity->get_table_alias('course_completion');
|
||||
$completionentity->add_joins($userentity->get_joins());
|
||||
$completionentity->add_join("
|
||||
LEFT JOIN {course_completions} {$completion}
|
||||
ON {$completion}.course = {$course}.id AND {$completion}.userid = {$user}.id
|
||||
");
|
||||
$completionentity->set_table_alias('user', $user);
|
||||
$this->add_entity($completionentity);
|
||||
|
||||
// Join course access entity.
|
||||
$accessentity = new access();
|
||||
$lastaccess = $accessentity->get_table_alias('user_lastaccess');
|
||||
$accessentity->add_joins($userentity->get_joins());
|
||||
$accessentity->add_join("
|
||||
LEFT JOIN {user_lastaccess} {$lastaccess}
|
||||
ON {$lastaccess}.userid = {$user}.id AND {$lastaccess}.courseid = {$course}.id
|
||||
");
|
||||
$this->add_entity($accessentity);
|
||||
|
||||
// Do not show deleted users.
|
||||
$this->add_base_condition_sql("{$user}.deleted = 0");
|
||||
|
||||
// Add all entities columns/filters/conditions.
|
||||
$this->add_all_from_entities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return user friendly name of the datasource
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name(): string {
|
||||
return get_string('courseparticipants', 'course');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the columns that will be added to the report as part of default setup
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_columns(): array {
|
||||
return [
|
||||
'course:coursefullnamewithlink',
|
||||
'enrolment:method',
|
||||
'user:fullnamewithlink',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that will be added to the report once is created
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_filters(): array {
|
||||
return [
|
||||
'user:suspended',
|
||||
'user:confirmed',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the conditions that will be added to the report once is created
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_conditions(): array {
|
||||
return [
|
||||
'user:suspended',
|
||||
'user:confirmed',
|
||||
];
|
||||
}
|
||||
}
|
138
course/classes/reportbuilder/local/entities/access.php
Normal file
138
course/classes/reportbuilder/local/entities/access.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?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_course\reportbuilder\local\entities;
|
||||
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\helpers\format;
|
||||
use core_reportbuilder\local\report\column;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Course access entity implementation
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class access extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_table_aliases(): array {
|
||||
return ['user_lastaccess' => 'ula', 'user' => 'u'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default title for this entity in the list of columns/conditions/filters in the report builder
|
||||
*
|
||||
* @return lang_string
|
||||
*/
|
||||
protected function get_default_entity_title(): lang_string {
|
||||
return new lang_string('courseaccess', 'course');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the entity
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public function initialise(): base {
|
||||
foreach ($this->get_all_columns() as $column) {
|
||||
$this->add_column($column);
|
||||
}
|
||||
|
||||
// All the filters defined by the entity can also be used as conditions.
|
||||
foreach ($this->get_all_filters() as $filter) {
|
||||
$this
|
||||
->add_filter($filter)
|
||||
->add_condition($filter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all available columns
|
||||
*
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
$tablealias = $this->get_table_alias('user_lastaccess');
|
||||
$user = $this->get_table_alias('user');
|
||||
|
||||
// Last course access column.
|
||||
$columns[] = (new column(
|
||||
'timeaccess',
|
||||
new lang_string('lastcourseaccess', 'moodle'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$tablealias}.timeaccess")
|
||||
->add_field("{$user}.id", 'userid')
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate'])
|
||||
->add_callback(static function(string $value, stdClass $row): string {
|
||||
if (!$row->userid) {
|
||||
return '';
|
||||
}
|
||||
if ($value === '') {
|
||||
return get_string('never');
|
||||
}
|
||||
return $value;
|
||||
});
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of all available filters
|
||||
*
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
$tablealias = $this->get_table_alias('user_lastaccess');
|
||||
|
||||
// Last course access filter.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timeaccess',
|
||||
new lang_string('lastcourseaccess', 'moodle'),
|
||||
$this->get_entity_name(),
|
||||
"{$tablealias}.timeaccess"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_limited_operators([
|
||||
date::DATE_ANY,
|
||||
date::DATE_NOT_EMPTY,
|
||||
date::DATE_EMPTY,
|
||||
date::DATE_RANGE,
|
||||
date::DATE_LAST,
|
||||
date::DATE_CURRENT,
|
||||
]);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
280
course/classes/reportbuilder/local/entities/completion.php
Normal file
280
course/classes/reportbuilder/local/entities/completion.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?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_course\reportbuilder\local\entities;
|
||||
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_course\reportbuilder\local\formatters\completion as completion_formatter;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\helpers\format;
|
||||
use core_reportbuilder\local\report\column;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Course completion entity implementation
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class completion extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_table_aliases(): array {
|
||||
return [
|
||||
'course_completion' => 'ccomp',
|
||||
'course' => 'c',
|
||||
'grade_grades' => 'gg',
|
||||
'grade_items' => 'gi',
|
||||
'user' => 'u',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default title for this entity in the list of columns/conditions/filters in the report builder
|
||||
*
|
||||
* @return lang_string
|
||||
*/
|
||||
protected function get_default_entity_title(): lang_string {
|
||||
return new lang_string('coursecompletion', 'completion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the entity
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public function initialise(): base {
|
||||
foreach ($this->get_all_columns() as $column) {
|
||||
$this->add_column($column);
|
||||
}
|
||||
|
||||
// All the filters defined by the entity can also be used as conditions.
|
||||
foreach ($this->get_all_filters() as $filter) {
|
||||
$this
|
||||
->add_filter($filter)
|
||||
->add_condition($filter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all available columns
|
||||
*
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
$coursecompletion = $this->get_table_alias('course_completion');
|
||||
$course = $this->get_table_alias('course');
|
||||
$grade = $this->get_table_alias('grade_grades');
|
||||
$gradeitem = $this->get_table_alias('grade_items');
|
||||
$user = $this->get_table_alias('user');
|
||||
|
||||
// Completed column.
|
||||
$columns[] = (new column(
|
||||
'completed',
|
||||
new lang_string('completed', 'completion'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_BOOLEAN)
|
||||
->add_field("CASE WHEN {$coursecompletion}.timecompleted > 0 THEN 1 ELSE 0 END", 'completed')
|
||||
->add_field("{$user}.id", 'userid')
|
||||
->set_is_sortable(true)
|
||||
->add_callback(static function(bool $value, stdClass $row): string {
|
||||
if (!$row->userid) {
|
||||
return '';
|
||||
}
|
||||
return format::boolean_as_text($value);
|
||||
});
|
||||
|
||||
// Progress percentage column.
|
||||
$columns[] = (new column(
|
||||
'progresspercent',
|
||||
new lang_string('progress', 'completion'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_field("{$course}.id", 'courseid')
|
||||
->add_field("{$user}.id", 'userid')
|
||||
->set_is_sortable(false)
|
||||
->add_callback([completion_formatter::class, 'completion_progress']);
|
||||
|
||||
// Time enrolled.
|
||||
$columns[] = (new column(
|
||||
'timeenrolled',
|
||||
new lang_string('timeenrolled', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$coursecompletion}.timeenrolled")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Time started.
|
||||
$columns[] = (new column(
|
||||
'timestarted',
|
||||
new lang_string('timestarted', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$coursecompletion}.timestarted")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Time completed.
|
||||
$columns[] = (new column(
|
||||
'timecompleted',
|
||||
new lang_string('timecompleted', 'completion'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$coursecompletion}.timecompleted")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Time reaggregated.
|
||||
$columns[] = (new column(
|
||||
'reaggregate',
|
||||
new lang_string('timereaggregated', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$coursecompletion}.reaggregate")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Days taking course (days since course start date until completion or until current date if not completed).
|
||||
$currenttime = time();
|
||||
$columns[] = (new column(
|
||||
'dayscourse',
|
||||
new lang_string('daystakingcourse', 'course'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_field("(
|
||||
CASE
|
||||
WHEN {$coursecompletion}.timecompleted > 0 THEN
|
||||
{$coursecompletion}.timecompleted
|
||||
ELSE
|
||||
{$currenttime}
|
||||
END - {$course}.startdate) / " . DAYSECS, 'dayscourse')
|
||||
->add_field("{$user}.id", 'userid')
|
||||
->set_is_sortable(true)
|
||||
->add_callback([completion_formatter::class, 'get_days']);
|
||||
|
||||
// Days since last completion (days since last enrolment date until completion or until current date if not completed).
|
||||
$columns[] = (new column(
|
||||
'daysuntilcompletion',
|
||||
new lang_string('daysuntilcompletion', 'completion'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_field("(
|
||||
CASE
|
||||
WHEN {$coursecompletion}.timecompleted > 0 THEN
|
||||
{$coursecompletion}.timecompleted
|
||||
ELSE
|
||||
{$currenttime}
|
||||
END - {$coursecompletion}.timeenrolled) / " . DAYSECS, 'daysuntilcompletion')
|
||||
->add_field("{$user}.id", 'userid')
|
||||
->set_is_sortable(true)
|
||||
->add_callback([completion_formatter::class, 'get_days']);
|
||||
|
||||
// Student course grade.
|
||||
$columns[] = (new column(
|
||||
'grade',
|
||||
new lang_string('gradenoun'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->add_join("
|
||||
LEFT JOIN {grade_items} {$gradeitem}
|
||||
ON ({$gradeitem}.itemtype = 'course' AND {$course}.id = {$gradeitem}.courseid)
|
||||
")
|
||||
->add_join("
|
||||
LEFT JOIN {grade_grades} {$grade}
|
||||
ON ({$user}.id = {$grade}.userid AND {$gradeitem}.id = {$grade}.itemid)
|
||||
")
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_fields("{$grade}.finalgrade")
|
||||
->set_is_sortable(true)
|
||||
->add_callback(function ($value) {
|
||||
if (!$value) {
|
||||
return '';
|
||||
}
|
||||
return format_float($value, 2);
|
||||
});
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of all available filters
|
||||
*
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
$coursecompletion = $this->get_table_alias('course_completion');
|
||||
|
||||
// Completed status filter.
|
||||
$filters[] = (new filter(
|
||||
boolean_select::class,
|
||||
'completed',
|
||||
new lang_string('completed', 'completion'),
|
||||
$this->get_entity_name(),
|
||||
"CASE WHEN {$coursecompletion}.timecompleted > 0 THEN 1 ELSE 0 END"
|
||||
))
|
||||
->add_joins($this->get_joins());
|
||||
|
||||
// Time completed filter.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timecompleted',
|
||||
new lang_string('timecompleted', 'completion'),
|
||||
$this->get_entity_name(),
|
||||
"{$coursecompletion}.timecompleted"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_limited_operators([
|
||||
date::DATE_ANY,
|
||||
date::DATE_NOT_EMPTY,
|
||||
date::DATE_EMPTY,
|
||||
date::DATE_RANGE,
|
||||
date::DATE_LAST,
|
||||
date::DATE_CURRENT,
|
||||
]);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
302
course/classes/reportbuilder/local/entities/enrolment.php
Normal file
302
course/classes/reportbuilder/local/entities/enrolment.php
Normal file
@ -0,0 +1,302 @@
|
||||
<?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_course\reportbuilder\local\entities;
|
||||
|
||||
use context_course;
|
||||
use core_course\reportbuilder\local\formatters\enrolment as enrolment_formatter;
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
use core_reportbuilder\local\helpers\format;
|
||||
use core_reportbuilder\local\report\column;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
use core_user\output\status_field;
|
||||
use enrol_plugin;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Course enrolment entity implementation
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class enrolment extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_table_aliases(): array {
|
||||
return ['user_enrolments' => 'ue', 'enrol' => 'e'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default title for this entity in the list of columns/conditions/filters in the report builder
|
||||
*
|
||||
* @return lang_string
|
||||
*/
|
||||
protected function get_default_entity_title(): lang_string {
|
||||
return new lang_string('enrolment', 'enrol');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the entity
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public function initialise(): base {
|
||||
foreach ($this->get_all_columns() as $column) {
|
||||
$this->add_column($column);
|
||||
}
|
||||
|
||||
// All the filters defined by the entity can also be used as conditions.
|
||||
foreach ($this->get_all_filters() as $filter) {
|
||||
$this
|
||||
->add_filter($filter)
|
||||
->add_condition($filter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all available columns
|
||||
*
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
$userenrolments = $this->get_table_alias('user_enrolments');
|
||||
$enrol = $this->get_table_alias('enrol');
|
||||
|
||||
// Enrolment method column.
|
||||
$columns[] = (new column(
|
||||
'method',
|
||||
new lang_string('method', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$enrol}.enrol, {$enrol}.id")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([enrolment_formatter::class, 'enrolment_name']);
|
||||
|
||||
// Enrolment time created.
|
||||
$columns[] = (new column(
|
||||
'timecreated',
|
||||
new lang_string('timecreated', 'moodle'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$userenrolments}.timecreated")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Enrolment time started.
|
||||
$columns[] = (new column(
|
||||
'timestarted',
|
||||
new lang_string('timestarted', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("
|
||||
CASE WHEN {$userenrolments}.timestart = 0
|
||||
THEN {$userenrolments}.timecreated
|
||||
ELSE {$userenrolments}.timestart
|
||||
END", 'timestarted')
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Enrolment time ended.
|
||||
$columns[] = (new column(
|
||||
'timeended',
|
||||
new lang_string('timeended', 'enrol'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$userenrolments}.timeend")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'userdate']);
|
||||
|
||||
// Enrolment status.
|
||||
$columns[] = (new column(
|
||||
'status',
|
||||
new lang_string('status', 'moodle'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_field($this->get_status_field_sql(), 'status')
|
||||
->add_field("{$userenrolments}.userid")
|
||||
->set_is_sortable(true)
|
||||
->add_callback([enrolment_formatter::class, 'enrolment_status']);
|
||||
|
||||
// Role method column.
|
||||
$ctx = database::generate_alias();
|
||||
$ra = database::generate_alias();
|
||||
$r = database::generate_alias();
|
||||
$columns[] = (new column(
|
||||
'role',
|
||||
new lang_string('role', 'moodle'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->add_join("LEFT JOIN {context} {$ctx}
|
||||
ON {$ctx}.instanceid = {$enrol}.courseid AND {$ctx}.contextlevel = " . CONTEXT_COURSE)
|
||||
->add_join("LEFT JOIN {role_assignments} {$ra}
|
||||
ON {$ra}.contextid = {$ctx}.id AND {$ra}.userid = {$userenrolments}.userid")
|
||||
->add_join("LEFT JOIN {role} {$r} ON {$r}.id = {$ra}.roleid")
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$r}.id, {$r}.name, {$r}.shortname, {$ctx}.instanceid")
|
||||
->set_is_sortable(true, ["{$r}.shortname"])
|
||||
->add_callback(static function(?string $value, stdClass $row): string {
|
||||
if (!$row->id) {
|
||||
return '';
|
||||
}
|
||||
$context = context_course::instance($row->instanceid);
|
||||
return role_get_name($row, $context, ROLENAME_ALIAS);
|
||||
});
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SQL snippet suitable for returning enrolment status field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_status_field_sql(): string {
|
||||
$time = time();
|
||||
$userenrolments = $this->get_table_alias('user_enrolments');
|
||||
$enrol = $this->get_table_alias('enrol');
|
||||
|
||||
return "
|
||||
CASE WHEN {$userenrolments}.status = " . ENROL_USER_ACTIVE . "
|
||||
THEN CASE WHEN ({$userenrolments}.timestart > {$time})
|
||||
OR ({$userenrolments}.timeend > 0 AND {$userenrolments}.timeend < {$time})
|
||||
OR ({$enrol}.status = " . ENROL_INSTANCE_DISABLED . ")
|
||||
THEN " . status_field::STATUS_NOT_CURRENT . "
|
||||
ELSE " . status_field::STATUS_ACTIVE . "
|
||||
END
|
||||
ELSE " . status_field::STATUS_SUSPENDED . "
|
||||
END";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of all available filters
|
||||
*
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
$userenrolments = $this->get_table_alias('user_enrolments');
|
||||
$enrol = $this->get_table_alias('enrol');
|
||||
|
||||
// Enrolment method.
|
||||
$enrolmentmethods = static function(): array {
|
||||
return array_map(static function(enrol_plugin $plugin): string {
|
||||
return get_string('pluginname', 'enrol_' . $plugin->get_name());
|
||||
}, enrol_get_plugins(true));
|
||||
};
|
||||
$filters[] = (new filter(
|
||||
select::class,
|
||||
'method',
|
||||
new lang_string('method', 'enrol'),
|
||||
$this->get_entity_name(),
|
||||
"{$enrol}.enrol"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_options_callback($enrolmentmethods);
|
||||
|
||||
// Enrolment time created.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timecreated',
|
||||
new lang_string('timecreated', 'moodle'),
|
||||
$this->get_entity_name(),
|
||||
"{$userenrolments}.timecreated"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_limited_operators([
|
||||
date::DATE_ANY,
|
||||
date::DATE_NOT_EMPTY,
|
||||
date::DATE_EMPTY,
|
||||
date::DATE_RANGE,
|
||||
date::DATE_LAST,
|
||||
date::DATE_CURRENT,
|
||||
]);
|
||||
|
||||
// Enrolment time started.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timestarted',
|
||||
new lang_string('timestarted', 'enrol'),
|
||||
$this->get_entity_name(),
|
||||
"CASE WHEN {$userenrolments}.timestart = 0
|
||||
THEN {$userenrolments}.timecreated
|
||||
ELSE {$userenrolments}.timestart
|
||||
END"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_limited_operators([
|
||||
date::DATE_ANY,
|
||||
date::DATE_NOT_EMPTY,
|
||||
date::DATE_EMPTY,
|
||||
date::DATE_RANGE,
|
||||
date::DATE_LAST,
|
||||
date::DATE_CURRENT,
|
||||
]);
|
||||
|
||||
// Enrolment time ended.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timeended',
|
||||
new lang_string('timeended', 'enrol'),
|
||||
$this->get_entity_name(),
|
||||
"{$userenrolments}.timeend"
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_limited_operators([
|
||||
date::DATE_ANY,
|
||||
date::DATE_NOT_EMPTY,
|
||||
date::DATE_EMPTY,
|
||||
date::DATE_RANGE,
|
||||
date::DATE_LAST,
|
||||
date::DATE_CURRENT,
|
||||
]);
|
||||
|
||||
// Enrolment status.
|
||||
$filters[] = (new filter(
|
||||
select::class,
|
||||
'status',
|
||||
new lang_string('status', 'moodle'),
|
||||
$this->get_entity_name(),
|
||||
$this->get_status_field_sql()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_options(enrolment_formatter::enrolment_values());
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
77
course/classes/reportbuilder/local/formatters/completion.php
Normal file
77
course/classes/reportbuilder/local/formatters/completion.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?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_course\reportbuilder\local\formatters;
|
||||
|
||||
use core_completion\progress;
|
||||
use core_reportbuilder\local\helpers\format;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Formatters for the course completion entity
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class completion {
|
||||
|
||||
/**
|
||||
* Return completion progress as a percentage
|
||||
*
|
||||
* @param string|null $value
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
public static function completion_progress(?string $value, stdClass $row): string {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/completionlib.php');
|
||||
|
||||
// Do not show progress if there is no userid.
|
||||
if (!$row->userid) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Make sure courseid and userid have a value, specially userid because get_course_progress_percentage() defaults
|
||||
// to the current user if this is null and the result would be wrong.
|
||||
$courseid = (int) $row->courseid;
|
||||
$userid = (int) $row->userid;
|
||||
if ($courseid === 0 || $userid === 0) {
|
||||
return format::percent(0);
|
||||
}
|
||||
|
||||
$course = get_course($courseid);
|
||||
$progress = (float) progress::get_course_progress_percentage($course, $userid);
|
||||
return format::percent($progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of days for methods daystakingcourse and daysuntilcompletion
|
||||
*
|
||||
* @param int $value
|
||||
* @param stdClass $row
|
||||
* @return int|null
|
||||
*/
|
||||
public static function get_days(int $value, stdClass $row): ?int {
|
||||
// Do not show anything if there is no userid.
|
||||
if (!$row->userid) {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
81
course/classes/reportbuilder/local/formatters/enrolment.php
Normal file
81
course/classes/reportbuilder/local/formatters/enrolment.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?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_course\reportbuilder\local\formatters;
|
||||
|
||||
use core_user\output\status_field;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Formatters for the course enrolment entity
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class enrolment {
|
||||
|
||||
/**
|
||||
* Return enrolment plugin instance name
|
||||
*
|
||||
* @param string|null $value
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
public static function enrolment_name(?string $value, stdClass $row): string {
|
||||
global $DB;
|
||||
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$instance = $DB->get_record('enrol', ['id' => $row->id, 'enrol' => $row->enrol], '*', MUST_EXIST);
|
||||
$plugin = enrol_get_plugin($row->enrol);
|
||||
|
||||
return $plugin ? $plugin->get_instance_name($instance) : '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of enrolment statuses
|
||||
*
|
||||
* @return lang_string[]
|
||||
*/
|
||||
public static function enrolment_values(): array {
|
||||
return [
|
||||
status_field::STATUS_ACTIVE => new lang_string('participationactive', 'enrol'),
|
||||
status_field::STATUS_SUSPENDED => new lang_string('participationsuspended', 'enrol'),
|
||||
status_field::STATUS_NOT_CURRENT => new lang_string('participationnotcurrent', 'enrol'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return enrolment status for user
|
||||
*
|
||||
* @param string $value
|
||||
* @param stdClass $row
|
||||
* @return lang_string|null
|
||||
*/
|
||||
public static function enrolment_status(string $value, stdClass $row): ?lang_string {
|
||||
if (!$row->userid) {
|
||||
return null;
|
||||
}
|
||||
$statusvalues = self::enrolment_values();
|
||||
return $statusvalues[(int) $value] ?? null;
|
||||
}
|
||||
}
|
280
course/tests/reportbuilder/datasource/participants_test.php
Normal file
280
course/tests/reportbuilder/datasource/participants_test.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?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_course\reportbuilder\datasource;
|
||||
|
||||
use completion_completion;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder_testcase;
|
||||
use grade_item;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
|
||||
require_once("{$CFG->libdir}/gradelib.php");
|
||||
|
||||
/**
|
||||
* Course participants datasource tests
|
||||
*
|
||||
* @package core_course
|
||||
* @covers \core_course\reportbuilder\datasource\participants
|
||||
* @covers \core_course\reportbuilder\local\formatters\completion
|
||||
* @covers \core_course\reportbuilder\local\formatters\enrolment
|
||||
* @copyright 2022 David Matamoros <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class participants_test extends core_reportbuilder_testcase {
|
||||
|
||||
/**
|
||||
* Test participants datasource
|
||||
*/
|
||||
public function test_participants_datasource(): void {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$timestart = time() - DAYSECS;
|
||||
$timeend = $timestart + 3 * DAYSECS;
|
||||
$timecompleted = $timestart + 2 * DAYSECS;
|
||||
$timelastaccess = time() + 4 * DAYSECS;
|
||||
|
||||
$category = $this->getDataGenerator()->create_category(['name' => 'Music']);
|
||||
$course = $this->getDataGenerator()->create_course([
|
||||
'category' => $category->id,
|
||||
'fullname' => 'All about Lionel at the work place',
|
||||
'enablecompletion' => true,
|
||||
'startdate' => $timestart,
|
||||
'enddate' => $timeend,
|
||||
]);
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student',
|
||||
'manual', $timestart, $timeend, ENROL_USER_ACTIVE);
|
||||
|
||||
// Mark course as completed for the user.
|
||||
$ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id));
|
||||
$ccompletion->mark_enrolled($timestart);
|
||||
$ccompletion->mark_complete($timecompleted);
|
||||
|
||||
// Update final grade for the user.
|
||||
$courseitem = grade_item::fetch_course_item($course->id);
|
||||
$courseitem->update_final_grade($user1->id, 80);
|
||||
|
||||
// Set some last access value for the user in the course.
|
||||
$DB->insert_record('user_lastaccess',
|
||||
['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]);
|
||||
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'course:fullname']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'course_category:name']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'user:fullname']);
|
||||
// Order by enrolment method.
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'enrolment:method'])
|
||||
->set('sortenabled', true)
|
||||
->update();
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:completed']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'access:timeaccess']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:progresspercent']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:timeenrolled']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:timestarted']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:timecompleted']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:reaggregate']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:dayscourse']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:daysuntilcompletion']);
|
||||
$generator->create_column(['reportid' => $report->get('id'),
|
||||
'uniqueidentifier' => 'completion:grade']);
|
||||
|
||||
// Add filter to the report.
|
||||
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
|
||||
// It should get 3 records (manual enrolment, self and guest).
|
||||
$this->assertCount(3, $content);
|
||||
|
||||
// Filter by Manual enrolment method.
|
||||
$content = $this->get_custom_report_content($report->get('id'), 30, [
|
||||
'enrolment:method_operator' => select::EQUAL_TO,
|
||||
'enrolment:method_value' => 'manual',
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
$this->assertEquals([
|
||||
'All about Lionel at the work place', // Course name.
|
||||
'Music', // Course category name.
|
||||
fullname($user1), // User fullname.
|
||||
'Manual enrolments', // Enrolment method.
|
||||
'Yes', // Course completed.
|
||||
userdate($timelastaccess), // Time last access.
|
||||
'100.0%', // Progress percentage.
|
||||
userdate($timestart), // Time enrolled.
|
||||
'', // Time started.
|
||||
userdate($timecompleted), // Time completed.
|
||||
'', // Reagreggate.
|
||||
'2', // Days taking course.
|
||||
'2', // Days until completion.
|
||||
'80.00', // Grade.
|
||||
], array_values($content[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for {@see test_report_filters}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters_data_provider(): array {
|
||||
return [
|
||||
[
|
||||
'enrolment:status',
|
||||
[
|
||||
'enrolment:status_operator' => select::EQUAL_TO,
|
||||
'enrolment:status_value' => 1,
|
||||
],
|
||||
'Luna'
|
||||
],
|
||||
[
|
||||
'enrolment:timecreated',
|
||||
[
|
||||
'enrolment:timecreated_operator' => date::DATE_CURRENT,
|
||||
'enrolment:timecreated_unit' => date::DATE_UNIT_DAY,
|
||||
],
|
||||
'Kira'
|
||||
],
|
||||
[
|
||||
'enrolment:timestarted',
|
||||
[
|
||||
'enrolment:timestarted_operator' => date::DATE_CURRENT,
|
||||
'enrolment:timecreated_unit' => date::DATE_UNIT_DAY,
|
||||
],
|
||||
'Luna'
|
||||
],
|
||||
[
|
||||
'enrolment:timeended',
|
||||
[
|
||||
'enrolment:timeended_operator' => date::DATE_CURRENT,
|
||||
'enrolment:timeended_unit' => date::DATE_UNIT_DAY,
|
||||
],
|
||||
'Luna'
|
||||
],
|
||||
[
|
||||
'completion:completed',
|
||||
[
|
||||
'completion:completed_operator' => boolean_select::CHECKED,
|
||||
'completion:completed_unit' => 1,
|
||||
],
|
||||
'Lionel'
|
||||
],
|
||||
[
|
||||
'completion:timecompleted',
|
||||
[
|
||||
'completion:timecompleted_operator' => date::DATE_NOT_EMPTY,
|
||||
],
|
||||
'Lionel'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting filter SQL
|
||||
*
|
||||
* @param string $filter
|
||||
* @param array $filtervalues
|
||||
* @param string $expected
|
||||
*
|
||||
* @dataProvider filters_data_provider
|
||||
*/
|
||||
public function test_report_filters(string $filter, array $filtervalues, string $expected): void {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$timestart = time() - DAYSECS;
|
||||
$timeend = $timestart + 3 * DAYSECS;
|
||||
$timecompleted = $timestart + 2 * DAYSECS;
|
||||
$timelastaccess = time() + 4 * DAYSECS;
|
||||
|
||||
$category = $this->getDataGenerator()->create_category(['name' => 'Music']);
|
||||
$course = $this->getDataGenerator()->create_course([
|
||||
'category' => $category->id,
|
||||
'fullname' => 'All about Lionel at the work place',
|
||||
'enablecompletion' => true,
|
||||
'startdate' => $timestart,
|
||||
'enddate' => $timeend,
|
||||
]);
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user(['firstname' => 'Lionel']);
|
||||
$user2 = self::getDataGenerator()->create_user(['firstname' => 'Kira']);
|
||||
$user3 = self::getDataGenerator()->create_user(['firstname' => 'Luna']);
|
||||
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student',
|
||||
'manual', $timestart - 8 * DAYSECS, $timeend, ENROL_USER_ACTIVE);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student',
|
||||
'manual', $timestart, $timeend, ENROL_USER_ACTIVE);
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student',
|
||||
'manual', time(), time(), ENROL_USER_SUSPENDED);
|
||||
|
||||
// Mark course as completed for the user.
|
||||
$ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id));
|
||||
$ccompletion->mark_enrolled($timestart);
|
||||
$ccompletion->mark_complete($timecompleted);
|
||||
|
||||
// Set some last access value for the user in the course.
|
||||
$DB->insert_record('user_lastaccess',
|
||||
['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]);
|
||||
|
||||
// Add user firstname column to the report.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname']);
|
||||
|
||||
$DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user1->id]);
|
||||
$DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user3->id]);
|
||||
|
||||
// Add filters to the report.
|
||||
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']);
|
||||
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filter]);
|
||||
|
||||
// Apply filters.
|
||||
$filtermanual = ['enrolment:method_operator' => select::EQUAL_TO, 'enrolment:method_value' => 'manual'];
|
||||
$content = $this->get_custom_report_content($report->get('id'), 30, $filtermanual + $filtervalues);
|
||||
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertEquals($expected, $content[0]['c0_firstname']);
|
||||
}
|
||||
}
|
@ -141,6 +141,7 @@ $string['csvdownload'] = 'Download in spreadsheet format (UTF-8 .csv)';
|
||||
$string['datepassed'] = 'Date passed';
|
||||
$string['days'] = 'Days';
|
||||
$string['daysoftotal'] = '{$a->days} of {$a->total}';
|
||||
$string['daysuntilcompletion'] = 'Days until completion';
|
||||
$string['defaultcompletion'] = 'Default activity completion';
|
||||
$string['defaultcompletionupdated'] = 'Changes saved';
|
||||
$string['deletecompletiondata'] = 'Delete completion data';
|
||||
@ -232,6 +233,7 @@ $string['selfcompletion'] = 'Self completion';
|
||||
$string['showcompletionconditions'] = 'Show activity completion conditions';
|
||||
$string['showcompletionconditions_help'] = 'Activity completion conditions are always shown on the activity page. This setting determines whether activity completion conditions are also shown below each activity on the course page.';
|
||||
$string['showinguser'] = 'Showing user';
|
||||
$string['timecompleted'] = 'Time completed';
|
||||
$string['todo'] = 'To do';
|
||||
$string['unenrolingfromcourse'] = 'Unenrolling from course';
|
||||
$string['unenrolment'] = 'Unenrolment';
|
||||
|
@ -60,6 +60,7 @@ $string['completion_setby:auto:todo'] = 'To do: {$a->condition} (set by {$a->set
|
||||
$string['completion_setby:manual:done'] = '{$a->activityname} is marked by {$a->setby} as done. Press to undo.';
|
||||
$string['completion_setby:manual:markdone'] = '{$a->activityname} is marked by {$a->setby} as not done. Press to mark as done.';
|
||||
$string['completionrequirements'] = 'Completion requirements for {$a}';
|
||||
$string['courseaccess'] = 'Course access';
|
||||
$string['coursealreadyfinished'] = 'Course already finished';
|
||||
$string['coursecontentnotification'] = 'Send content change notification';
|
||||
$string['coursecontentnotifnew'] = '{$a->coursename} new content';
|
||||
@ -69,6 +70,7 @@ $string['coursecontentnotifupdatebody'] = '<p>{$a->moduletypename} <a href="{$a-
|
||||
$string['coursecontentnotification_help'] = 'Tick the box to notify course participants about this new or changed activity or resource. Only users who can access the activity or resource will receive the notification.';
|
||||
$string['coursenotyetstarted'] = 'The course has not yet started';
|
||||
$string['coursenotyetfinished'] = 'The course has not yet finished';
|
||||
$string['courseparticipants'] = 'Course participants';
|
||||
$string['coursetoolong'] = 'The course is too long';
|
||||
$string['customfield_islocked'] = 'Locked';
|
||||
$string['customfield_islocked_help'] = 'If the field is locked, only users with the capability to change locked custom fields (by default users with the default role of manager only) will be able to change it in the course settings.';
|
||||
@ -78,6 +80,7 @@ $string['customfield_visibility_help'] = 'This setting determines who can view t
|
||||
$string['customfield_visibletoall'] = 'Everyone';
|
||||
$string['customfield_visibletoteachers'] = 'Teachers';
|
||||
$string['customfieldsettings'] = 'Common course custom fields settings';
|
||||
$string['daystakingcourse'] = 'Days taking course';
|
||||
$string['downloadcourseconfirmation'] = 'You are about to download a zip file of course content (excluding items which cannot be downloaded and any files larger than {$a}).';
|
||||
$string['downloadcoursecontent'] = 'Download course content';
|
||||
$string['downloadcoursecontent_help'] = 'This setting determines whether course content may be downloaded by users with the download course content capability (by default users with the role of student or teacher).';
|
||||
|
@ -58,6 +58,7 @@ $string['enrollednewusers'] = 'Successfully enrolled {$a} new users';
|
||||
$string['enrolledusers'] = 'Enrolled users';
|
||||
$string['enrolledusersmatching'] = 'Matching enrolled users';
|
||||
$string['enrolme'] = 'Enrol me in this course';
|
||||
$string['enrolment'] = 'Enrolment';
|
||||
$string['enrolmentinstances'] = 'Enrolment methods';
|
||||
$string['enrolmentnew'] = 'New enrolment in {$a}';
|
||||
$string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"';
|
||||
@ -102,6 +103,7 @@ $string['invalidrole'] = 'Invalid role';
|
||||
$string['invalidrequest'] = 'Invalid request';
|
||||
$string['manageenrols'] = 'Manage enrol plugins';
|
||||
$string['manageinstance'] = 'Manage';
|
||||
$string['method'] = 'Method';
|
||||
$string['migratetomanual'] = 'Migrate to manual enrolments';
|
||||
$string['nochange'] = 'No change';
|
||||
$string['noexistingparticipants'] = 'No existing participants';
|
||||
@ -131,6 +133,10 @@ $string['startdatetoday'] = 'Today';
|
||||
$string['synced'] = 'Synced';
|
||||
$string['testsettings'] = 'Test settings';
|
||||
$string['testsettingsheading'] = 'Test enrol settings - {$a}';
|
||||
$string['timeended'] = 'Time ended';
|
||||
$string['timeenrolled'] = 'Time enrolled';
|
||||
$string['timereaggregated'] = 'Time reaggregated';
|
||||
$string['timestarted'] = 'Time started';
|
||||
$string['totalenrolledusers'] = '{$a} enrolled users';
|
||||
$string['totalunenrolledusers'] = '{$a} unenrolled users';
|
||||
$string['totalotherusers'] = '{$a} other users';
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use core_reportbuilder\local\helpers\user_filter_manager;
|
||||
use core_reportbuilder\table\custom_report_table_view;
|
||||
|
||||
/**
|
||||
@ -32,11 +33,15 @@ abstract class core_reportbuilder_testcase extends advanced_testcase {
|
||||
*
|
||||
* @param int $reportid
|
||||
* @param int $pagesize
|
||||
* @param array $filtervalues
|
||||
* @return array[]
|
||||
*/
|
||||
protected function get_custom_report_content(int $reportid, int $pagesize = 30): array {
|
||||
protected function get_custom_report_content(int $reportid, int $pagesize = 30, array $filtervalues = []): array {
|
||||
$records = [];
|
||||
|
||||
// Apply filter values.
|
||||
user_filter_manager::set($reportid, $filtervalues);
|
||||
|
||||
// Create table instance.
|
||||
$table = custom_report_table_view::create($reportid);
|
||||
$table->setup();
|
||||
|
@ -31,3 +31,4 @@ Information provided here is intended especially for developers.
|
||||
* New report filter types:
|
||||
- `category` for reports containing course categories
|
||||
- `tags` for reports containing entities with support for core_tag API
|
||||
* The helper method `get_custom_report_content()` now accepts a list of filters and applies them to the report
|
Loading…
x
Reference in New Issue
Block a user