This commit is contained in:
Huong Nguyen 2024-07-25 11:01:56 +07:00
commit 2b724556ee
No known key found for this signature in database
GPG Key ID: 40D88AB693A3E72A
4 changed files with 279 additions and 210 deletions

View File

@ -18,18 +18,13 @@ declare(strict_types=1);
namespace core_reportbuilder\local\helpers;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\filters\number;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\filters\text;
use core_reportbuilder\local\report\column;
use core_reportbuilder\local\report\filter;
use lang_string;
use stdClass;
use core\lang_string;
use core_customfield\data_controller;
use core_customfield\field_controller;
use core_customfield\handler;
use core_reportbuilder\local\filters\{boolean_select, date, number, select, text};
use core_reportbuilder\local\report\{column, filter};
use stdClass;
/**
* Helper class for course custom fields.
@ -116,24 +111,31 @@ class custom_fields {
foreach ($categorieswithfields as $fieldcategory) {
$categoryfields = $fieldcategory->get_fields();
foreach ($categoryfields as $field) {
$customdatatablealias = $this->get_table_alias($field);
$datacontroller = data_controller::create(0, null, $field);
$datafield = $datacontroller->datafield();
$datafieldsql = "{$customdatatablealias}.{$datafield}";
// Long text fields should be cast for Oracle, for aggregation support.
$customdatatablealias = $this->get_table_alias($field);
$customdatasql = "{$customdatatablealias}.{$datafield}";
// Numeric column (non-text) should coalesce with default, as should text fields for Oracle, for aggregation.
$columntype = $this->get_column_type($field, $datafield);
if ($columntype === column::TYPE_LONGTEXT && $DB->get_dbfamily() === 'oracle') {
$datafieldsql = $DB->sql_order_by_text($datafieldsql, 1024);
if (!in_array($columntype, [column::TYPE_TEXT, column::TYPE_LONGTEXT])) {
// See MDL-78783 regarding no bound parameters, and Oracle limitations of GROUP BY.
$customdatasql = "
CASE WHEN {$this->tablefieldalias} IS NOT NULL
THEN COALESCE({$customdatasql}, " . (float) $datacontroller->get_default_value() . ")
ELSE NULL
END";
} else if ($columntype === column::TYPE_LONGTEXT && $DB->get_dbfamily() === 'oracle') {
$customdatasql = $DB->sql_order_by_text($customdatasql, 1024);
}
// Select enough fields to re-create and format each custom field instance value.
$selectfields = "{$customdatatablealias}.id, {$customdatatablealias}.contextid";
$customdatasqlextra = "{$customdatatablealias}.id, {$customdatatablealias}.contextid";
if ($datafield === 'value') {
// We will take the format into account when displaying the individual values.
$selectfields .= ", {$customdatatablealias}.valueformat, {$customdatatablealias}.valuetrust";
$customdatasqlextra .= ", {$customdatatablealias}.valueformat, {$customdatatablealias}.valuetrust";
}
$columns[] = (new column(
@ -143,15 +145,19 @@ class custom_fields {
))
->add_joins($this->get_joins())
->add_join($this->get_table_join($field))
->add_field($datafieldsql, $datafield)
->add_fields($selectfields)
->add_field($customdatasql, $datafield)
->add_fields($customdatasqlextra)
->add_field($this->tablefieldalias, 'tablefieldalias')
->set_type($columntype)
->set_is_sortable($columntype !== column::TYPE_LONGTEXT)
->add_callback(static function($value, stdClass $row, field_controller $field): string {
if ($row->tablefieldalias === null) {
->add_callback(static function($value, stdClass $row, field_controller $field, ?string $aggregation): string {
if ($row->tablefieldalias === null && $value === null) {
return '';
}
// If aggregating numeric column, populate row ID to ensure the controller is created correctly.
if (in_array((string) $aggregation, ['avg', 'max', 'min', 'sum'])) {
$row->id ??= -1;
}
return (string) data_controller::create(0, $row, $field)->export_value();
}, $field)
// Important. If the handler implements can_view() function, it will be called with parameter $instanceid=0.
@ -213,23 +219,42 @@ class custom_fields {
foreach ($categorieswithfields as $fieldcategory) {
$categoryfields = $fieldcategory->get_fields();
foreach ($categoryfields as $field) {
$customdatatablealias = $this->get_table_alias($field);
$datacontroller = data_controller::create(0, null, $field);
$datafield = $datacontroller->datafield();
$datafieldsql = "{$customdatatablealias}.{$datafield}";
$customdatatablealias = $this->get_table_alias($field);
$customdatasql = "{$customdatatablealias}.{$datafield}";
$customdataparams = [];
if ($datafield === 'value') {
$datafieldsql = $DB->sql_cast_to_char($datafieldsql);
$customdatasql = $DB->sql_cast_to_char($customdatasql);
}
// Account for field default value, when joined to the instance table related to the custom fields.
if (($fielddefault = $datacontroller->get_default_value()) !== null) {
$paramdefault = database::generate_param_name();
// Oracle be crazy.
$paramdefaultsql = ":{$paramdefault}";
if ($DB->get_dbfamily() === 'oracle' && in_array($datafield, ['intvalue', 'decvalue'])) {
$paramdefaultsql = $DB->sql_cast_char2int($paramdefaultsql);
}
$customdatasql = "
CASE WHEN {$this->tablefieldalias} IS NOT NULL
THEN COALESCE({$customdatasql}, {$paramdefaultsql})
ELSE NULL
END";
$customdataparams[$paramdefault] = $fielddefault;
}
$typeclass = $this->get_filter_class_type($datacontroller);
$filter = (new filter(
$typeclass,
$this->get_filter_class_type($datacontroller),
'customfield_' . $field->get('shortname'),
new lang_string('customfieldcolumn', 'core_reportbuilder', $field->get_formatted_name()),
$this->entityname,
$datafieldsql
$customdatasql,
$customdataparams,
))
->add_joins($this->get_joins())
->add_join($this->get_table_join($field));

View File

@ -18,15 +18,11 @@ declare(strict_types=1);
namespace core_reportbuilder\local\helpers;
use context_system;
use core\context\system;
use core\lang_string;
use core_text;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\filters\text;
use core_reportbuilder\local\report\column;
use core_reportbuilder\local\report\filter;
use lang_string;
use core_reportbuilder\local\filters\{boolean_select, date, select, text};
use core_reportbuilder\local\report\{column, filter};
use profile_field_base;
use stdClass;
@ -111,37 +107,53 @@ class user_profile_fields {
global $DB;
$columns = [];
foreach ($this->userprofilefields as $profilefield) {
$columntype = $this->get_user_field_type($profilefield->field->datatype);
$columnfieldsql = $this->get_table_alias($profilefield) . '.data';
// Numeric (checkbox/time) fields should be cast, as should all fields for Oracle, for aggregation support.
if ($columntype === column::TYPE_BOOLEAN || $columntype === column::TYPE_TIMESTAMP) {
$columnfieldsql = "CASE WHEN {$columnfieldsql} IS NULL THEN NULL ELSE " .
$DB->sql_cast_char2int($columnfieldsql, true) . " END";
} else if ($DB->get_dbfamily() === 'oracle') {
$columnfieldsql = $DB->sql_order_by_text($columnfieldsql, 1024);
foreach ($this->userprofilefields as $profilefield) {
$userinfotablealias = $this->get_table_alias($profilefield);
$userinfosql = "{$userinfotablealias}.data";
if ($DB->get_dbfamily() === 'oracle') {
$userinfosql = $DB->sql_order_by_text($userinfosql, 1024);
}
// Numeric column (non-text) should cast/coalesce with default, as should all fields for Oracle, for aggregation.
$columntype = $this->get_user_field_type($profilefield->field->datatype);
if (!in_array($columntype, [column::TYPE_TEXT, column::TYPE_LONGTEXT])) {
// See MDL-78783 regarding no bound parameters, and Oracle limitations of GROUP BY.
$userinfosql = "
CASE WHEN {$this->usertablefieldalias} IS NOT NULL
THEN " .
$DB->sql_cast_char2int("COALESCE({$userinfosql}, '" . (float) $profilefield->field->defaultdata . "')")
. "
ELSE NULL
END";
}
$columns[] = (new column(
'profilefield_' . core_text::strtolower($profilefield->field->shortname),
new lang_string('customfieldcolumn', 'core_reportbuilder',
format_string($profilefield->field->name, true,
['escape' => false, 'context' => context_system::instance()])),
format_string($profilefield->field->name, true, ['escape' => false, 'context' => system::instance()])),
$this->entityname
))
->add_joins($this->get_joins())
->add_join($this->get_table_join($profilefield))
->add_field($columnfieldsql, 'data')
->add_field($userinfosql, 'data')
->add_field("{$userinfotablealias}.dataformat")
->add_field($this->usertablefieldalias, 'userid')
->set_type($columntype)
->set_is_sortable($columntype !== column::TYPE_LONGTEXT)
->add_callback(static function($value, stdClass $row, profile_field_base $field): string {
if ($value === null) {
if ($row->userid === null && $value === null) {
return '';
}
$field->data = $value;
return (string) $field->display_data();
$field->set_user_data(
$row->data ?? $field->field->defaultdata,
$row->dataformat ?? $field->field->defaultdataformat,
);
return $field->display_data();
}, $profilefield);
}
@ -157,48 +169,60 @@ class user_profile_fields {
global $DB;
$filters = [];
foreach ($this->userprofilefields as $profilefield) {
$field = $this->get_table_alias($profilefield) . '.data';
$params = [];
foreach ($this->userprofilefields as $profilefield) {
$userinfotablealias = $this->get_table_alias($profilefield);
$userinfosql = "{$userinfotablealias}.data";
$userinfoparams = [];
// Perform casts where necessary, as this is a text DB field.
switch ($profilefield->field->datatype) {
case 'checkbox':
$classname = boolean_select::class;
$fieldsql = "COALESCE(" . $DB->sql_cast_char2int($field, true) . ", 0)";
$userinfosql = $DB->sql_cast_char2int($userinfosql, true);
break;
case 'datetime':
$classname = date::class;
$fieldsql = $DB->sql_cast_char2int($field, true);
$userinfosql = $DB->sql_cast_char2int($userinfosql, true);
break;
case 'menu':
$classname = select::class;
$emptyparam = database::generate_param_name();
$fieldsql = "COALESCE(" . $DB->sql_compare_text($field, 255) . ", :{$emptyparam})";
$params[$emptyparam] = '';
$userinfosql = $DB->sql_cast_to_char($userinfosql);
break;
case 'text':
case 'textarea':
default:
$classname = text::class;
$emptyparam = database::generate_param_name();
$fieldsql = "COALESCE(" . $DB->sql_compare_text($field, 255) . ", :{$emptyparam})";
$params[$emptyparam] = '';
$userinfosql = $DB->sql_cast_to_char($userinfosql);
break;
}
// Account for field default value, when joined to the user table.
if (($fielddefault = $profilefield->field->defaultdata) !== null) {
$paramdefault = database::generate_param_name();
// Oracle be crazy.
$paramdefaultsql = ":{$paramdefault}";
if ($DB->get_dbfamily() === 'oracle' && in_array($profilefield->field->datatype, ['checkbox', 'datetime'])) {
$paramdefaultsql = $DB->sql_cast_char2int($paramdefaultsql);
}
$userinfosql = "
CASE WHEN {$this->usertablefieldalias} IS NOT NULL
THEN COALESCE({$userinfosql}, {$paramdefaultsql})
ELSE NULL
END";
$userinfoparams[$paramdefault] = $fielddefault;
}
$filter = (new filter(
$classname,
'profilefield_' . core_text::strtolower($profilefield->field->shortname),
new lang_string('customfieldcolumn', 'core_reportbuilder',
format_string($profilefield->field->name, true,
['escape' => false, 'context' => context_system::instance()])),
format_string($profilefield->field->name, true, ['escape' => false, 'context' => system::instance()])),
$this->entityname,
$fieldsql,
$params
$userinfosql,
$userinfoparams,
))
->add_joins($this->get_joins())
->add_join($this->get_table_join($profilefield));

View File

@ -22,12 +22,8 @@ use core_customfield_generator;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\entities\course;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\filters\text;
use core_reportbuilder\local\report\column;
use core_reportbuilder\local\report\filter;
use core_reportbuilder\local\filters\{boolean_select, date, select, text};
use core_reportbuilder\local\report\{column, filter};
use core_course\reportbuilder\datasource\{categories, courses};
defined('MOODLE_INTERNAL') || die();
@ -62,13 +58,16 @@ final class custom_fields_test extends core_reportbuilder_testcase {
]);
$generator->create_field(
['categoryid' => $category->get('id'), 'type' => 'text', 'name' => 'Text', 'shortname' => 'text']);
['categoryid' => $category->get('id'), 'type' => 'text', 'name' => 'Text', 'shortname' => 'text',
'configdata' => ['defaultvalue' => 'default']]);
$generator->create_field(
['categoryid' => $category->get('id'), 'type' => 'textarea', 'name' => 'Textarea', 'shortname' => 'textarea']);
['categoryid' => $category->get('id'), 'type' => 'textarea', 'name' => 'Textarea', 'shortname' => 'textarea',
'configdata' => ['defaultvalue' => 'Default']]);
$generator->create_field(
['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox']);
['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox',
'configdata' => ['checkbydefault' => 1]]);
$generator->create_field(
['categoryid' => $category->get('id'), 'type' => 'date', 'name' => 'Date', 'shortname' => 'date']);
@ -81,8 +80,7 @@ final class custom_fields_test extends core_reportbuilder_testcase {
$coursealias = $courseentity->get_table_alias('course');
// Create an instance of the customfields helper.
return new custom_fields($coursealias . '.id', $courseentity->get_entity_name(),
'core_course', 'course');
return new custom_fields("{$coursealias}.id", $courseentity->get_entity_name(), 'core_course', 'course');
}
/**
@ -172,51 +170,19 @@ final class custom_fields_test extends core_reportbuilder_testcase {
public function test_custom_report_content(): void {
$this->resetAfterTest();
$this->generate_customfields();
$category = $this->getDataGenerator()->create_category(['name' => 'Zebras']);
$courseone = $this->getDataGenerator()->create_course(['category' => $category->id, 'fullname' => 'C1']);
$course = $this->getDataGenerator()->create_course(['customfields' => [
// Second course will populate each custom field.
$this->generate_customfields();
$coursetwo = $this->getDataGenerator()->create_course(['category' => $category->id, 'fullname' => 'C2', 'customfields' => [
['shortname' => 'text', 'value' => 'Hello'],
['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
['shortname' => 'checkbox', 'value' => true],
['shortname' => 'checkbox', 'value' => 0],
['shortname' => 'date', 'value' => 1669852800],
['shortname' => 'select', 'value' => 2],
]]);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
// Add custom field columns to the report.
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_text']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_textarea']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_checkbox']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_date']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_select']);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertEquals([
$course->fullname,
'Hello',
'<div class="text_to_html">Goodbye</div>',
'Yes',
userdate(1669852800),
'Dog'
], array_values($content[0]));
}
/**
* Test that adding custom field columns to report returns expected default values for fields
*/
public function test_custom_report_content_column_defaults(): void {
$this->resetAfterTest();
$this->generate_customfields();
$category = $this->getDataGenerator()->create_category(['name' => 'Zebras']);
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Categories', 'source' => categories::class, 'default' => 0]);
@ -224,13 +190,43 @@ final class custom_fields_test extends core_reportbuilder_testcase {
// Add custom field columns to the report.
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:name',
'sortenabled' => 1]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname',
'sortenabled' => 1]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_text']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_textarea']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_checkbox']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_date']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_select']);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertEquals([
['Category 1', '', ''],
[$category->name, $course->fullname, 'Cat'],
[
'Category 1',
'',
'',
'',
'',
'',
'',
],
[
$category->name,
$courseone->fullname,
'default',
format_text('Default'),
'Yes',
'',
'Cat',
],
[
$category->name,
$coursetwo->fullname,
'Hello',
format_text('Goodbye'),
'No',
userdate(1669852800),
'Dog',
],
], array_map('array_values', $content));
}
@ -244,41 +240,53 @@ final class custom_fields_test extends core_reportbuilder_testcase {
'Filter by text custom field' => ['course:customfield_text', [
'course:customfield_text_operator' => text::IS_EQUAL_TO,
'course:customfield_text_value' => 'Hello',
], true],
], 'C2'],
'Filter by text custom field (default)' => ['course:customfield_text', [
'course:customfield_text_operator' => text::IS_EQUAL_TO,
'course:customfield_text_value' => 'default',
], 'C1'],
'Filter by text custom field (no match)' => ['course:customfield_text', [
'course:customfield_text_operator' => text::IS_EQUAL_TO,
'course:customfield_text_value' => 'Goodbye',
], false],
]],
'Filter by textarea custom field' => ['course:customfield_textarea', [
'course:customfield_textarea_operator' => text::IS_EQUAL_TO,
'course:customfield_textarea_value' => 'Goodbye',
], true],
], 'C2'],
'Filter by textarea custom field (default)' => ['course:customfield_textarea', [
'course:customfield_textarea_operator' => text::IS_EQUAL_TO,
'course:customfield_textarea_value' => 'Default',
], 'C1'],
'Filter by textarea custom field (no match)' => ['course:customfield_textarea', [
'course:customfield_textarea_operator' => text::IS_EQUAL_TO,
'course:customfield_textarea_value' => 'Hello',
], false],
]],
'Filter by checkbox custom field' => ['course:customfield_checkbox', [
'course:customfield_checkbox_operator' => boolean_select::CHECKED,
], true],
'Filter by checkbox custom field (no match)' => ['course:customfield_checkbox', [
'course:customfield_checkbox_operator' => boolean_select::NOT_CHECKED,
], false],
], 'C2'],
'Filter by checkbox custom field (default)' => ['course:customfield_checkbox', [
'course:customfield_checkbox_operator' => boolean_select::CHECKED,
], 'C1'],
'Filter by date custom field' => ['course:customfield_date', [
'course:customfield_date_operator' => date::DATE_RANGE,
'course:customfield_date_from' => 1622502000,
], true],
], 'C2'],
'Filter by date custom field (no match)' => ['course:customfield_date', [
'course:customfield_date_operator' => date::DATE_RANGE,
'course:customfield_date_to' => 1622502000,
], false],
'course:customfield_date_from' => 1672531200,
]],
'Filter by select custom field' => ['course:customfield_select', [
'course:customfield_select_operator' => select::EQUAL_TO,
'course:customfield_select_value' => 2,
], true],
'Filter by select custom field (no match)' => ['course:customfield_select', [
], 'C2'],
'Filter by select custom field (default)' => ['course:customfield_select', [
'course:customfield_select_operator' => select::EQUAL_TO,
'course:customfield_select_value' => 1,
], false],
], 'C1'],
'Filter by select custom field (no match)' => ['course:customfield_select', [
'course:customfield_select_operator' => select::EQUAL_TO,
'course:customfield_select_value' => 3,
]],
];
}
@ -287,19 +295,21 @@ final class custom_fields_test extends core_reportbuilder_testcase {
*
* @param string $filtername
* @param array $filtervalues
* @param bool $expectmatch
* @param string|null $expectmatch
*
* @dataProvider custom_report_filter_provider
*/
public function test_custom_report_filter(string $filtername, array $filtervalues, bool $expectmatch): void {
public function test_custom_report_filter(string $filtername, array $filtervalues, ?string $expectmatch = null): void {
$this->resetAfterTest();
$this->generate_customfields();
$this->getDataGenerator()->create_course(['fullname' => 'C1']);
$course = $this->getDataGenerator()->create_course(['customfields' => [
// Second course will populate each custom field.
$this->generate_customfields();
$this->getDataGenerator()->create_course(['fullname' => 'C2', 'customfields' => [
['shortname' => 'text', 'value' => 'Hello'],
['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
['shortname' => 'checkbox', 'value' => true],
['shortname' => 'checkbox', 'value' => 0],
['shortname' => 'date', 'value' => 1669852800],
['shortname' => 'select', 'value' => 2],
]]);
@ -315,9 +325,9 @@ final class custom_fields_test extends core_reportbuilder_testcase {
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
$content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
if ($expectmatch) {
if ($expectmatch !== null) {
$this->assertCount(1, $content);
$this->assertEquals($course->fullname, reset($content[0]));
$this->assertEquals($expectmatch, reset($content[0]));
} else {
$this->assertEmpty($content);
}
@ -336,7 +346,7 @@ final class custom_fields_test extends core_reportbuilder_testcase {
$this->resetAfterTest();
$this->generate_customfields();
$course = $this->getDataGenerator()->create_course(['customfields' => [
$this->getDataGenerator()->create_course(['customfields' => [
['shortname' => 'text', 'value' => 'Hello'],
['shortname' => 'textarea_editor', 'value' => ['text' => 'Goodbye', 'format' => FORMAT_MOODLE]],
['shortname' => 'checkbox', 'value' => true],

View File

@ -21,12 +21,8 @@ namespace core_reportbuilder\local\helpers;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\filters\text;
use core_reportbuilder\local\report\column;
use core_reportbuilder\local\report\filter;
use core_reportbuilder\local\filters\{boolean_select, date, select, text};
use core_reportbuilder\local\report\{column, filter};
use core_user\reportbuilder\datasource\users;
defined('MOODLE_INTERNAL') || die();
@ -51,28 +47,29 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
*/
private function generate_userprofilefields(): user_profile_fields {
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'checkbox', 'name' => 'Checkbox field', 'datatype' => 'checkbox']);
'shortname' => 'checkbox', 'name' => 'Checkbox field', 'datatype' => 'checkbox', 'defaultdata' => 1]);
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'datetime', 'name' => 'Date field', 'datatype' => 'datetime', 'param2' => 2022, 'param3' => 0]);
'shortname' => 'datetime', 'name' => 'Date field', 'datatype' => 'datetime', 'param2' => 2022, 'param3' => 0,
'defaultdata' => 0]);
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'menu', 'name' => 'Menu field', 'datatype' => 'menu', 'param1' => "Cat\nDog"]);
'shortname' => 'menu', 'name' => 'Menu field', 'datatype' => 'menu', 'param1' => "Cat\nDog", 'defaultdata' => 'Cat']);
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'Social', 'name' => 'msn', 'datatype' => 'social', 'param1' => 'msn']);
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'text', 'name' => 'Text field', 'datatype' => 'text']);
'shortname' => 'text', 'name' => 'Text field', 'datatype' => 'text', 'defaultdata' => 'default']);
$this->getDataGenerator()->create_custom_profile_field([
'shortname' => 'textarea', 'name' => 'Textarea field', 'datatype' => 'textarea']);
'shortname' => 'textarea', 'name' => 'Textarea field', 'datatype' => 'textarea', 'defaultdata' => 'Default']);
$userentity = new user();
$useralias = $userentity->get_table_alias('user');
// Create an instance of the userprofilefield helper.
return new user_profile_fields("$useralias.id", $userentity->get_entity_name());
return new user_profile_fields("{$useralias}.id", $userentity->get_entity_name());
}
/**
@ -207,14 +204,13 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
public function test_custom_report_content(): void {
$this->resetAfterTest();
$userprofilefields = $this->generate_userprofilefields();
// Create test subject with user profile fields content.
$user = $this->getDataGenerator()->create_user([
$this->generate_userprofilefields();
$this->getDataGenerator()->create_user([
'firstname' => 'Zebedee',
'profile_field_checkbox' => true,
'profile_field_checkbox' => 0,
'profile_field_datetime' => '2021-12-09',
'profile_field_menu' => 'Cat',
'profile_field_menu' => 'Dog',
'profile_field_Social' => 12345,
'profile_field_text' => 'Hello',
'profile_field_textarea' => 'Goodbye',
@ -225,7 +221,7 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
$report = $generator->create_report(['name' => 'Users', 'source' => users::class, 'default' => 0]);
// Add user profile field columns to the report.
$firstname = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname', 'sortenabled' => 1]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_checkbox']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_datetime']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_menu']);
@ -233,29 +229,26 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_text']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_textarea']);
// Sort the report, Admin -> Zebedee for consistency.
report::toggle_report_column_sorting($report->get('id'), $firstname->get('id'), true);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertEquals([
[
'c0_firstname' => 'Admin',
'c1_data' => '',
'c2_data' => '',
'c3_data' => '',
'c4_data' => '',
'c5_data' => '',
'c6_data' => '',
'Admin',
'Yes',
'Not set',
'Cat',
'',
'default',
format_text('Default', options: ['overflowdiv' => true]),
], [
'c0_firstname' => 'Zebedee',
'c1_data' => 'Yes',
'c2_data' => '9 December 2021',
'c3_data' => 'Cat',
'c4_data' => '12345',
'c5_data' => 'Hello',
'c6_data' => '<div class="no-overflow">Goodbye</div>',
'Zebedee',
'No',
'9 December 2021',
'Dog',
'12345',
'Hello',
format_text('Goodbye', options: ['overflowdiv' => true]),
],
], $content);
], array_map('array_values', $content));
}
/**
@ -266,49 +259,63 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
public static function custom_report_filter_provider(): array {
return [
'Filter by checkbox profile field' => ['user:profilefield_checkbox', [
'user:profilefield_checkbox_operator' => boolean_select::CHECKED,
], 'testuser'],
'Filter by checkbox profile field (empty)' => ['user:profilefield_checkbox', [
'user:profilefield_checkbox_operator' => boolean_select::NOT_CHECKED,
], 'testuser'],
'Filter by checkbox profile field (default)' => ['user:profilefield_checkbox', [
'user:profilefield_checkbox_operator' => boolean_select::CHECKED,
], 'admin'],
'Filter by datetime profile field' => ['user:profilefield_datetime', [
'user:profilefield_datetime_operator' => date::DATE_RANGE,
'user:profilefield_datetime_from' => 1622502000,
], 'testuser'],
'Filter by datetime profile field (empty)' => ['user:profilefield_datetime', [
'user:profilefield_datetime_operator' => date::DATE_EMPTY,
], 'admin'],
'Filter by datetime profile field (no match)' => ['user:profilefield_datetime', [
'user:profilefield_datetime_operator' => date::DATE_RANGE,
'user:profilefield_datetime_from' => 1672531200,
]],
'Filter by menu profile field' => ['user:profilefield_menu', [
'user:profilefield_menu_operator' => select::EQUAL_TO,
'user:profilefield_menu_value' => 'Dog',
], 'testuser'],
'Filter by menu profile field (empty)' => ['user:profilefield_menu', [
'user:profilefield_menu_operator' => select::NOT_EQUAL_TO,
'user:profilefield_menu_value' => 'Dog',
'Filter by menu profile field (default)' => ['user:profilefield_menu', [
'user:profilefield_menu_operator' => select::EQUAL_TO,
'user:profilefield_menu_value' => 'Cat',
], 'admin'],
'Filter by menu profile field (no match)' => ['user:profilefield_menu', [
'user:profilefield_menu_operator' => select::EQUAL_TO,
'user:profilefield_menu_value' => 'Fish',
]],
'Filter by social profile field' => ['user:profilefield_social', [
'user:profilefield_social_operator' => text::IS_EQUAL_TO,
'user:profilefield_social_value' => '12345',
], 'testuser'],
'Filter by social profile field (empty)' => ['user:profilefield_social', [
'user:profilefield_social_operator' => text::IS_EMPTY,
], 'admin'],
'Filter by social profile field (no match)' => ['user:profilefield_social', [
'user:profilefield_social_operator' => text::IS_EQUAL_TO,
'user:profilefield_social_value' => '54321',
]],
'Filter by text profile field' => ['user:profilefield_text', [
'user:profilefield_text_operator' => text::IS_EQUAL_TO,
'user:profilefield_text_value' => 'Hello',
], 'testuser'],
'Filter by text profile field (empty)' => ['user:profilefield_text', [
'user:profilefield_text_operator' => text::IS_NOT_EQUAL_TO,
'user:profilefield_text_value' => 'Hello',
'Filter by text profile field (default)' => ['user:profilefield_text', [
'user:profilefield_text_operator' => text::IS_EQUAL_TO,
'user:profilefield_text_value' => 'default',
], 'admin'],
'Filter by text profile field (no match)' => ['user:profilefield_text', [
'user:profilefield_text_operator' => text::IS_EQUAL_TO,
'user:profilefield_text_value' => 'hola',
]],
'Filter by textarea profile field' => ['user:profilefield_textarea', [
'user:profilefield_textarea_operator' => text::IS_EQUAL_TO,
'user:profilefield_textarea_value' => 'Goodbye',
], 'testuser'],
'Filter by textarea profile field (empty)' => ['user:profilefield_textarea', [
'user:profilefield_textarea_operator' => text::DOES_NOT_CONTAIN,
'user:profilefield_textarea_value' => 'Goodbye',
'Filter by textarea profile field (default)' => ['user:profilefield_textarea', [
'user:profilefield_textarea_operator' => text::IS_EQUAL_TO,
'user:profilefield_textarea_value' => 'Default',
], 'admin'],
'Filter by textarea profile field (no match)' => ['user:profilefield_textarea', [
'user:profilefield_textarea_operator' => text::IS_EMPTY,
'user:profilefield_textarea_value' => 'Adios',
]],
];
}
@ -317,19 +324,18 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
*
* @param string $filtername
* @param array $filtervalues
* @param string $expectmatchuser
* @param string|null $expectmatch
*
* @dataProvider custom_report_filter_provider
*/
public function test_custom_report_filter(string $filtername, array $filtervalues, string $expectmatchuser): void {
public function test_custom_report_filter(string $filtername, array $filtervalues, ?string $expectmatch = null): void {
$this->resetAfterTest();
$userprofilefields = $this->generate_userprofilefields();
// Create test subject with user profile fields content.
$user = $this->getDataGenerator()->create_user([
$this->generate_userprofilefields();
$this->getDataGenerator()->create_user([
'username' => 'testuser',
'profile_field_checkbox' => true,
'profile_field_checkbox' => 0,
'profile_field_datetime' => '2021-12-09',
'profile_field_menu' => 'Dog',
'profile_field_Social' => '12345',
@ -348,8 +354,12 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
$content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
$this->assertCount(1, $content);
$this->assertEquals($expectmatchuser, reset($content[0]));
if ($expectmatch !== null) {
$this->assertCount(1, $content);
$this->assertEquals($expectmatch, reset($content[0]));
} else {
$this->assertEmpty($content);
}
}
/**
@ -364,8 +374,8 @@ final class user_profile_fields_test extends core_reportbuilder_testcase {
$this->resetAfterTest();
$userprofilefields = $this->generate_userprofilefields();
$user = $this->getDataGenerator()->create_user([
$this->generate_userprofilefields();
$this->getDataGenerator()->create_user([
'profile_field_checkbox' => true,
'profile_field_datetime' => '2021-12-09',
'profile_field_menu' => 'Dog',