diff --git a/reportbuilder/classes/local/helpers/custom_fields.php b/reportbuilder/classes/local/helpers/custom_fields.php
index 3d078970f2f..a2e45a79141 100644
--- a/reportbuilder/classes/local/helpers/custom_fields.php
+++ b/reportbuilder/classes/local/helpers/custom_fields.php
@@ -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));
diff --git a/reportbuilder/classes/local/helpers/user_profile_fields.php b/reportbuilder/classes/local/helpers/user_profile_fields.php
index bb2addfc5c9..3899225976c 100644
--- a/reportbuilder/classes/local/helpers/user_profile_fields.php
+++ b/reportbuilder/classes/local/helpers/user_profile_fields.php
@@ -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));
diff --git a/reportbuilder/tests/local/helpers/custom_fields_test.php b/reportbuilder/tests/local/helpers/custom_fields_test.php
index 759857da88b..2e03c3cb262 100644
--- a/reportbuilder/tests/local/helpers/custom_fields_test.php
+++ b/reportbuilder/tests/local/helpers/custom_fields_test.php
@@ -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',
- '
Goodbye
',
- '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],
diff --git a/reportbuilder/tests/local/helpers/user_profile_fields_test.php b/reportbuilder/tests/local/helpers/user_profile_fields_test.php
index 321a4603666..bdd7874c3e2 100644
--- a/reportbuilder/tests/local/helpers/user_profile_fields_test.php
+++ b/reportbuilder/tests/local/helpers/user_profile_fields_test.php
@@ -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' => 'Goodbye
',
+ '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',