MDL-76295 reportbuilder: implement default datasource sorting.

Update all existing report sources to use the new default sorting
API from 064eccd4, updating existing tests to assert behaviour.
This commit is contained in:
Paul Holden 2022-11-14 10:08:15 +00:00
parent b3c2a9fd15
commit 33a63ca639
No known key found for this signature in database
GPG Key ID: A81A96D6045F6164
20 changed files with 201 additions and 107 deletions

View File

@ -78,6 +78,17 @@ class task_logs extends datasource {
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'task_log:starttime' => SORT_DESC,
];
}
/**
* Return the filters that will be added to the report upon creation
*

View File

@ -46,17 +46,24 @@ class task_logs_test extends core_reportbuilder_testcase {
$this->resetAfterTest();
$this->generate_task_log_data(true, 3, 2, 1654038000, 1654038060);
$this->generate_task_log_data(false, 5, 1, 1654556400, 1654556700);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Tasks', 'source' => task_logs::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
$this->assertCount(2, $content);
// Default columns are name, starttime, duration, result.
// Default columns are name, start time, duration, result. Sorted by start time descending.
[$name, $timestart, $duration, $result] = array_values($content[0]);
$this->assertStringContainsString(send_schedules::class, $name);
$this->assertEquals('7/06/22, 07:00:00', $timestart);
$this->assertEquals('5 mins', $duration);
$this->assertEquals('Fail', $result);
[$name, $timestart, $duration, $result] = array_values($content[1]);
$this->assertStringContainsString(send_schedules::class, $name);
$this->assertEquals('1/06/22, 07:00:00', $timestart);
$this->assertEquals('1 min', $duration);
$this->assertEquals('Success', $result);

View File

@ -143,6 +143,18 @@ class blogs extends datasource {
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'user:fullname' => SORT_ASC,
'blog:timecreated' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*

View File

@ -21,7 +21,6 @@ namespace core_blog\reportbuilder\datasource;
use context_system;
use context_user;
use core_blog_generator;
use core_collator;
use core_comment_generator;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
@ -51,17 +50,19 @@ class blogs_test extends core_reportbuilder_testcase {
/** @var core_blog_generator $blogsgenerator */
$blogsgenerator = $this->getDataGenerator()->get_plugin_generator('core_blog');
// Our first user will create a course blog.
$course = $this->getDataGenerator()->create_course();
$usercourseblog = $this->getDataGenerator()->create_and_enrol($course);
$courseblog = $blogsgenerator->create_entry(['publishstate' => 'site', 'userid' => $usercourseblog->id,
$userone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
$courseblog = $blogsgenerator->create_entry(['publishstate' => 'site', 'userid' => $userone->id,
'subject' => 'Course', 'summary' => 'Course summary', 'courseid' => $course->id]);
$userpersonalblog = $this->getDataGenerator()->create_user();
$personalblog = $blogsgenerator->create_entry(['publishstate' => 'draft', 'userid' => $userpersonalblog->id,
// Our second user will create a personal and site blog.
$usertwo = $this->getDataGenerator()->create_user(['firstname' => 'Amy']);
$personalblog = $blogsgenerator->create_entry(['publishstate' => 'draft', 'userid' => $usertwo->id,
'subject' => 'Personal', 'summary' => 'Personal summary']);
$usersiteblog = $this->getDataGenerator()->create_user();
$siteblog = $blogsgenerator->create_entry(['publishstate' => 'public', 'userid' => $usersiteblog->id,
$this->waitForSecond(); // For consistent ordering we need distinct time for second user blogs.
$siteblog = $blogsgenerator->create_entry(['publishstate' => 'public', 'userid' => $usertwo->id,
'subject' => 'Site', 'summary' => 'Site summary']);
/** @var core_reportbuilder_generator $generator */
@ -69,17 +70,12 @@ class blogs_test extends core_reportbuilder_testcase {
$report = $generator->create_report(['name' => 'Blogs', 'source' => blogs::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(3, $content);
// Consistent order (course, personal, site), just in case.
core_collator::asort_array_of_arrays_by_key($content, 'c2_subject');
$content = array_values($content);
// Default columns are user, course, title, timecreated.
// Default columns are user, course, title, time created. Sorted by user and time created.
$this->assertEquals([
[fullname($usercourseblog), $course->fullname, $courseblog->subject, userdate($courseblog->created)],
[fullname($userpersonalblog), '', $personalblog->subject, userdate($personalblog->created)],
[fullname($usersiteblog), '', $siteblog->subject, userdate($siteblog->created)],
[fullname($usertwo), '', $personalblog->subject, userdate($personalblog->created)],
[fullname($usertwo), '', $siteblog->subject, userdate($siteblog->created)],
[fullname($userone), $course->fullname, $courseblog->subject, userdate($courseblog->created)],
], array_map('array_values', $content));
}

View File

@ -75,13 +75,25 @@ class comments extends datasource {
*/
public function get_default_columns(): array {
return [
'user:fullname',
'context:name',
'comment:content',
'user:fullname',
'comment:timecreated',
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'user:fullname' => SORT_ASC,
'comment:timecreated' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*

View File

@ -172,7 +172,8 @@ class comment extends base {
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$commentalias}.component");
->add_fields("{$commentalias}.component")
->set_is_sortable(true);
// Area.
$columns[] = (new column(
@ -182,7 +183,8 @@ class comment extends base {
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$commentalias}.commentarea");
->add_fields("{$commentalias}.commentarea")
->set_is_sortable(true);
// Item ID.
$columns[] = (new column(
@ -193,6 +195,7 @@ class comment extends base {
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_fields("{$commentalias}.itemid")
->set_is_sortable(true)
->set_disabled_aggregation_all();
// Time created.

View File

@ -34,15 +34,18 @@ class core_comment_generator extends component_generator_base {
* Create comment
*
* @param array|stdClass $record
* @return comment
*/
public function create_comment($record): comment {
$record = (array) $record;
$content = $record['content'] ?? '';
$content = (string) ($record['content'] ?? '');
unset($record['content']);
$comment = new comment((object) $record);
$comment->add($content);
if ($content !== '') {
$comment->add($content);
}
return $comment;
}

View File

@ -44,34 +44,51 @@ class comments_test extends core_reportbuilder_testcase {
*/
public function test_datasource_default(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
/** @var core_comment_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_comment');
$generator->create_comment([
// Our first user will create a single comment.
$userone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
$this->setUser($userone);
$useronecomment = $generator->create_comment([
'context' => $coursecontext,
'component' => 'block_comments',
'area' => 'page_comments',
'content' => 'Cool',
]);
])->add('Cool');
// Our second user will create a couple of comments.
$usertwo = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Amy']);
$this->setUser($usertwo);
$usertwocommentfirst = $generator->create_comment([
'context' => $coursecontext,
'component' => 'block_comments',
'area' => 'page_comments',
])->add('Super');
$this->waitForSecond(); // For consistent ordering we need distinct time for second user comments.
$usertwocommentsecond = $generator->create_comment([
'context' => $coursecontext,
'component' => 'block_comments',
'area' => 'page_comments',
])->add('Awesome');
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Blogs', 'source' => comments::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
// Default columns are context, content, user, time created.
[$contextname, $content, $userfullname, $timecreated] = array_values($content[0]);
$this->assertEquals($coursecontext->get_context_name(), $contextname);
$this->assertEquals(format_text('Cool'), $content);
$this->assertEquals(fullname(get_admin()), $userfullname);
$this->assertNotEmpty($timecreated);
// Default columns are user, context, content, time created. Sorted by user and time created.
$contextname = $coursecontext->get_context_name();
$this->assertEquals([
[fullname($usertwo), $contextname, format_text('Super'), userdate($usertwocommentfirst->timecreated)],
[fullname($usertwo), $contextname, format_text('Awesome'), userdate($usertwocommentsecond->timecreated)],
[fullname($userone), $contextname, format_text('Cool'), userdate($useronecomment->timecreated)],
], array_map('array_values', $content));
}
/**

View File

@ -53,7 +53,7 @@ class categories_test extends core_reportbuilder_testcase {
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(2, $content);
// Default columns are name, idnumber, coursecount. Sorted by name descending.
// Default columns are name, idnumber, coursecount. Sorted by name ascending.
$this->assertEquals([
[get_string('defaultcategoryname'), '', 0],
[$category->get_formatted_name(), $category->idnumber, 1],

View File

@ -51,7 +51,13 @@ class courses_test extends core_reportbuilder_testcase {
// Test subject.
$category = $this->getDataGenerator()->create_category(['name' => 'My cats']);
$course = $this->getDataGenerator()->create_course([
$courseone = $this->getDataGenerator()->create_course([
'category' => $category->id,
'fullname' => 'Feline fine',
'shortname' => 'C102',
'idnumber' => 'CAT102'
]);
$coursetwo = $this->getDataGenerator()->create_course([
'category' => $category->id,
'fullname' => 'All about cats',
'shortname' => 'C101',
@ -63,16 +69,12 @@ class courses_test extends core_reportbuilder_testcase {
$report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
$contentrow = array_values($content[0]);
// Default columns are category, shortname, fullname, idnumber. Sorted by category, shortname, fullname.
$this->assertEquals([
$category->get_formatted_name(),
$course->shortname,
$course->fullname,
$course->idnumber,
], $contentrow);
[$category->name, $coursetwo->shortname, $coursetwo->fullname, $coursetwo->idnumber],
[$category->name, $courseone->shortname, $courseone->fullname, $courseone->idnumber],
], array_map('array_values', $content));
}
/**

View File

@ -86,6 +86,18 @@ class files extends datasource {
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'context:name' => SORT_ASC,
'file:timecreated' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*

View File

@ -20,7 +20,6 @@ namespace core_files\reportbuilder\datasource;
use context_course;
use context_user;
use core_collator;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\filters\{boolean_select, date, number, select, text};
@ -67,13 +66,8 @@ class files_test extends core_reportbuilder_testcase {
$this->assertCount(2, $content);
// Consistent order (course, user), just in case.
core_collator::asort_array_of_arrays_by_key($content, 'c0_ctxid');
$content = array_values($content);
// First row (course summary file).
// Default columns are context, user, name, type, size, time created. Sorted by context and time created.
[$contextname, $userfullname, $filename, $mimetype, $filesize, $timecreated] = array_values($content[0]);
$this->assertEquals($coursecontext->get_context_name(), $contextname);
$this->assertEquals(fullname($user), $userfullname);
$this->assertEquals('Hello.txt', $filename);
@ -81,9 +75,7 @@ class files_test extends core_reportbuilder_testcase {
$this->assertEquals("5\xc2\xa0bytes", $filesize);
$this->assertNotEmpty($timecreated);
// Second row (user draft file).
[$contextname, $userfullname, $filename, $mimetype, $filesize, $timecreated] = array_values($content[1]);
$this->assertEquals($usercontext->get_context_name(), $contextname);
$this->assertEquals(fullname($user), $userfullname);
$this->assertEquals('Hello.txt', $filename);
@ -332,7 +324,7 @@ class files_test extends core_reportbuilder_testcase {
}
/**
* Helper method to generate some test files for reporting on
* Helper method to generate some test files (a user draft and course summary file) for reporting on
*
* @param context_course $context
* @return int Draft item ID

View File

@ -112,6 +112,19 @@ class groups extends datasource {
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'course:coursefullnamewithlink' => SORT_ASC,
'group:name' => SORT_ASC,
'user:fullname' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report as part of default setup
*

View File

@ -44,24 +44,28 @@ class groups_test extends core_reportbuilder_testcase {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_and_enrol($course, 'student');
$userone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
$usertwo = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Amy']);
$group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
$this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
$groupone = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Zebras']);
$grouptwo = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Aardvarks']);
$this->getDataGenerator()->create_group_member(['groupid' => $groupone->id, 'userid' => $userone->id]);
$this->getDataGenerator()->create_group_member(['groupid' => $groupone->id, 'userid' => $usertwo->id]);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
$contentrow = array_values(reset($content));
// Default columns are course, group, user. Sorted by each.
$courseurl = course_get_url($course);
$this->assertEquals([
"<a href=\"https://www.example.com/moodle/course/view.php?id={$course->id}\">{$course->fullname}</a>", // Course.
$group->name, // Group.
fullname($user), // User.
], $contentrow);
["<a href=\"{$courseurl}\">{$course->fullname}</a>", $grouptwo->name, ''],
["<a href=\"{$courseurl}\">{$course->fullname}</a>", $groupone->name, fullname($usertwo)],
["<a href=\"{$courseurl}\">{$course->fullname}</a>", $groupone->name, fullname($userone)],
], array_map('array_values', $content));
}
/**

View File

@ -105,6 +105,19 @@ class notes extends datasource {
'note:publishstate',
'course:fullname',
'note:content',
'note:timecreated',
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'recipient:fullname' => SORT_ASC,
'note:timecreated' => SORT_ASC,
];
}

View File

@ -18,7 +18,6 @@ declare(strict_types=1);
namespace core_notes\reportbuilder\datasource;
use core_collator;
use core_notes_generator;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
@ -56,17 +55,19 @@ class notes_test extends core_reportbuilder_testcase {
/** @var core_notes_generator $notesgenerator */
$notesgenerator = $this->getDataGenerator()->get_plugin_generator('core_notes');
// Our first user will create a course note.
$course = $this->getDataGenerator()->create_course();
$usercoursenote = $this->getDataGenerator()->create_and_enrol($course);
$notesgenerator->create_instance(['courseid' => $course->id, 'userid' => $usercoursenote->id, 'content' => 'Course',
$userone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
$coursenote = $notesgenerator->create_instance(['courseid' => $course->id, 'userid' => $userone->id, 'content' => 'Course',
'publishstate' => NOTES_STATE_PUBLIC]);
$userpersonalnote = $this->getDataGenerator()->create_user();
$notesgenerator->create_instance(['courseid' => $course->id, 'userid' => $userpersonalnote->id, 'content' => 'Personal',
// Our second user will create a personal and site note.
$usertwo = $this->getDataGenerator()->create_user(['firstname' => 'Amy']);
$personalnote = $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $usertwo->id, 'content' => 'Personal',
'publishstate' => NOTES_STATE_DRAFT]);
$usersitenote = $this->getDataGenerator()->create_user();
$notesgenerator->create_instance(['courseid' => $course->id, 'userid' => $usersitenote->id, 'content' => 'Site',
$this->waitForSecond(); // For consistent ordering we need distinct time for second user notes.
$sitenote = $notesgenerator->create_instance(['courseid' => SITEID, 'userid' => $usertwo->id, 'content' => 'Site',
'publishstate' => NOTES_STATE_SITE]);
/** @var core_reportbuilder_generator $generator */
@ -74,17 +75,12 @@ class notes_test extends core_reportbuilder_testcase {
$report = $generator->create_report(['name' => 'Notes', 'source' => notes::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(3, $content);
// Consistent order (course, personal, site), just in case.
core_collator::asort_array_of_arrays_by_key($content, 'c1_publishstate');
$content = array_values($content);
// Default columns are recipient, publishstate, course, note.
// Default columns are recipient, publishstate, course, note, time created. Sorted by recipient and time created.
$this->assertEquals([
[fullname($usercoursenote), 'Course notes', $course->fullname, 'Course'],
[fullname($userpersonalnote), 'Personal notes', '', 'Personal'],
[fullname($usersitenote), 'Site notes', '', 'Site'],
[fullname($usertwo), 'Personal notes', '', 'Personal', userdate($personalnote->created)],
[fullname($usertwo), 'Site notes', '', 'Site', userdate($sitenote->created)],
[fullname($userone), 'Course notes', $course->fullname, 'Course', userdate($coursenote->created)],
], array_map('array_values', $content));
}

View File

@ -102,6 +102,18 @@ class tags extends datasource {
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'collection:name' => SORT_ASC,
'tag:namewithlink' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*

View File

@ -20,7 +20,6 @@ namespace core_tag\reportbuilder\datasource;
use context_course;
use context_user;
use core_collator;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\filters\{boolean_select, date, select};
@ -47,12 +46,12 @@ class tags_test extends core_reportbuilder_testcase {
public function test_datasource_default(): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course(['tags' => ['Horses']]);
$coursecontext = context_course::instance($course->id);
$user = $this->getDataGenerator()->create_user(['interests' => ['Pies']]);
$usercontext = context_user::instance($user->id);
$course = $this->getDataGenerator()->create_course(['tags' => ['Horses']]);
$coursecontext = context_course::instance($course->id);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Notes', 'source' => tags::class, 'default' => 1]);
@ -60,22 +59,18 @@ class tags_test extends core_reportbuilder_testcase {
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(2, $content);
// Consistent order (course, user), just in case.
core_collator::asort_array_of_arrays_by_key($content, 'c3_ctxid');
$content = array_values($content);
// Default columns are collection, tag (with link), standard, context. Sorted by collection and tag.
[$collection, $tag, $standard, $context] = array_values($content[0]);
$this->assertEquals('Default collection', $collection);
$this->assertStringContainsString('Horses', $tag);
$this->assertEquals('No', $standard);
$this->assertEquals($coursecontext->get_context_name(), $context);
// Default columns are collection, tag name, tag standard, instance context.
[$courserow, $userrow] = array_map('array_values', $content);
$this->assertEquals('Default collection', $courserow[0]);
$this->assertStringContainsString('Horses', $courserow[1]);
$this->assertEquals('No', $courserow[2]);
$this->assertEquals($coursecontext->get_context_name(), $courserow[3]);
$this->assertEquals('Default collection', $userrow[0]);
$this->assertStringContainsString('Pies', $userrow[1]);
$this->assertEquals('No', $courserow[2]);
$this->assertEquals($usercontext->get_context_name(), $userrow[3]);
[$collection, $tag, $standard, $context] = array_values($content[1]);
$this->assertEquals('Default collection', $collection);
$this->assertStringContainsString('Pies', $tag);
$this->assertEquals('No', $standard);
$this->assertEquals($usercontext->get_context_name(), $context);
}
/**

View File

@ -24,8 +24,6 @@ use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\helpers\database;
use core_tag\reportbuilder\local\entities\tag;
use core_reportbuilder\manager;
use core_reportbuilder\local\helpers\report;
/**
* Users datasource

View File

@ -18,7 +18,6 @@ declare(strict_types=1);
namespace core_user\reportbuilder\datasource;
use core_collator;
use core_reportbuilder_testcase;
use core_reportbuilder_generator;
use core_reportbuilder\local\filters\boolean_select;
@ -86,7 +85,8 @@ class users_test extends core_reportbuilder_testcase {
$report = $generator->create_report(['name' => 'Users', 'source' => users::class, 'default' => 0]);
// User.
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:fullnamewithlink']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:fullnamewithlink',
'sortenabled' => 1]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:fullnamewithpicture']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:fullnamewithpicturelink']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:picture']);
@ -118,10 +118,6 @@ class users_test extends core_reportbuilder_testcase {
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(2, $content);
// Consistent order by firstname, just in case.
core_collator::asort_array_of_arrays_by_key($content, 'c4_firstname');
$content = array_values($content);
[$adminrow, $userrow] = array_map('array_values', $content);
$this->assertStringContainsString('Admin User', $adminrow[0]);