diff --git a/reportbuilder/classes/local/entities/course.php b/reportbuilder/classes/local/entities/course.php index 7d4586c045e..a21ea0a51f4 100644 --- a/reportbuilder/classes/local/entities/course.php +++ b/reportbuilder/classes/local/entities/course.php @@ -74,30 +74,27 @@ class course extends base { } /** - * Get custom fields helper - * - * @return custom_fields - */ - protected function get_custom_fields(): custom_fields { - $customfields = new custom_fields($this->get_table_alias('course') . '.id', $this->get_entity_name(), - 'core_course', 'course'); - $customfields->add_joins($this->get_joins()); - return $customfields; - } - - /** - * Initialise the entity, adding all course and custom course fields + * Initialise the entity * * @return base */ public function initialise(): base { - $customfields = $this->get_custom_fields(); + $tablealias = $this->get_table_alias('course'); + + $customfields = (new custom_fields( + "{$tablealias}.id", + $this->get_entity_name(), + 'core_course', + 'course', + )) + ->add_joins($this->get_joins()); $columns = array_merge($this->get_all_columns(), $customfields->get_columns()); foreach ($columns as $column) { $this->add_column($column); } + // All the filters defined by the entity can also be used as conditions. $filters = array_merge($this->get_all_filters(), $customfields->get_filters()); foreach ($filters as $filter) { $this diff --git a/reportbuilder/classes/local/helpers/custom_fields.php b/reportbuilder/classes/local/helpers/custom_fields.php index 241348da70c..7493372c317 100644 --- a/reportbuilder/classes/local/helpers/custom_fields.php +++ b/reportbuilder/classes/local/helpers/custom_fields.php @@ -266,13 +266,12 @@ class custom_fields { $datafieldsql )) ->add_joins($this->get_joins()) - ->add_join($this->get_table_join($field)); + ->add_join($this->get_table_join($field)) + ->set_is_available($this->handler->can_view($field, 0)); - // Options are stored inside configdata json string and we need to convert it to array. - if ($field->get('type') === 'select') { - $filter->set_options_callback(static function() use ($field): array { - return $field->get_options(); - }); + // If using a select filter, then populate the options. + if ($filter->get_filter_class() === select::class) { + $filter->set_options_callback(fn(): array => $field->get_options()); } $filters[] = $filter; diff --git a/reportbuilder/classes/local/helpers/user_profile_fields.php b/reportbuilder/classes/local/helpers/user_profile_fields.php index 74b416c7b6c..9991a77f0f6 100644 --- a/reportbuilder/classes/local/helpers/user_profile_fields.php +++ b/reportbuilder/classes/local/helpers/user_profile_fields.php @@ -64,18 +64,7 @@ class user_profile_fields { public function __construct(string $usertablefieldalias, string $entityname) { $this->usertablefieldalias = $usertablefieldalias; $this->entityname = $entityname; - $this->userprofilefields = $this->get_user_profile_fields(); - } - - /** - * Retrieves the list of available/visible user profile fields - * - * @return profile_field_base[] - */ - private function get_user_profile_fields(): array { - return array_filter(profile_get_user_fields_with_data(0), static function(profile_field_base $profilefield): bool { - return $profilefield->is_visible(); - }); + $this->userprofilefields = profile_get_user_fields_with_data(0); } /** @@ -183,7 +172,8 @@ class user_profile_fields { $field->data = $value; return (string) $field->display_data(); - }, $profilefield); + }, $profilefield) + ->set_is_available($profilefield->is_visible()); } return $columns; @@ -240,11 +230,12 @@ class user_profile_fields { $params )) ->add_joins($this->get_joins()) - ->add_join($this->get_table_join($profilefield)); + ->add_join($this->get_table_join($profilefield)) + ->set_is_available($profilefield->is_visible()); - // If menu type then set filter options as appropriate. - if ($profilefield->field->datatype === 'menu') { - $filter->set_options($profilefield->options); + // If using a select filter, then populate the options. + if ($filter->get_filter_class() === select::class) { + $filter->set_options_callback(fn(): array => $profilefield->options); } $filters[] = $filter; diff --git a/reportbuilder/tests/local/helpers/custom_fields_test.php b/reportbuilder/tests/local/helpers/custom_fields_test.php index 35abb77cf5f..468f2a63526 100644 --- a/reportbuilder/tests/local/helpers/custom_fields_test.php +++ b/reportbuilder/tests/local/helpers/custom_fields_test.php @@ -67,8 +67,10 @@ class custom_fields_test extends core_reportbuilder_testcase { $generator->create_field( ['categoryid' => $category->get('id'), 'type' => 'textarea', 'name' => 'Textarea', 'shortname' => 'textarea']); + // This field is available only to course teachers. $generator->create_field( - ['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox']); + ['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox', + 'configdata' => ['visibility' => 1]]); $generator->create_field( ['categoryid' => $category->get('id'), 'type' => 'date', 'name' => 'Date', 'shortname' => 'date']); @@ -90,10 +92,11 @@ class custom_fields_test extends core_reportbuilder_testcase { */ public function test_get_columns(): void { $this->resetAfterTest(); + $this->setAdminUser(); $customfields = $this->generate_customfields(); - $columns = $customfields->get_columns(); + $columns = $customfields->get_columns(); $this->assertCount(5, $columns); $this->assertContainsOnlyInstancesOf(column::class, $columns); @@ -114,6 +117,19 @@ class custom_fields_test extends core_reportbuilder_testcase { [true, false, true, true, true], array_map(fn(column $column) => $column->get_is_sortable(), $columns) ); + + // Column available. + $this->assertEquals( + [true, true, true, true, true], + array_map(fn(column $column) => $column->get_is_available(), $columns), + ); + + // Column available, for non-privileged user. + $this->setUser(null); + $this->assertEquals( + [true, true, false, true, true], + array_map(fn(column $column) => $column->get_is_available(), $customfields->get_columns()), + ); } /** @@ -167,18 +183,32 @@ class custom_fields_test extends core_reportbuilder_testcase { */ public function test_get_filters(): void { $this->resetAfterTest(); + $this->setAdminUser(); $customfields = $this->generate_customfields(); - $filters = $customfields->get_filters(); + $filters = $customfields->get_filters(); $this->assertCount(5, $filters); $this->assertContainsOnlyInstancesOf(filter::class, $filters); - // Filter titles. + // Filter headers. $this->assertEquals( ['Text', 'Textarea', 'Checkbox', 'Date', 'Select'], array_map(fn(filter $filter) => $filter->get_header(), $filters) ); + + // Filter available. + $this->assertEquals( + [true, true, true, true, true], + array_map(fn(filter $filter) => $filter->get_is_available(), $filters), + ); + + // Filter available, for non-privileged user. + $this->setUser(null); + $this->assertEquals( + [true, true, false, true, true], + array_map(fn(filter $filter) => $filter->get_is_available(), $customfields->get_filters()), + ); } /** @@ -186,6 +216,7 @@ class custom_fields_test extends core_reportbuilder_testcase { */ public function test_custom_report_content(): void { $this->resetAfterTest(); + $this->setAdminUser(); $this->generate_customfields(); @@ -308,6 +339,7 @@ class custom_fields_test extends core_reportbuilder_testcase { */ public function test_custom_report_filter(string $filtername, array $filtervalues, bool $expectmatch): void { $this->resetAfterTest(); + $this->setAdminUser(); $this->generate_customfields(); diff --git a/reportbuilder/tests/local/helpers/user_profile_fields_test.php b/reportbuilder/tests/local/helpers/user_profile_fields_test.php index c8c35f9e571..8301b98ae5d 100644 --- a/reportbuilder/tests/local/helpers/user_profile_fields_test.php +++ b/reportbuilder/tests/local/helpers/user_profile_fields_test.php @@ -53,8 +53,10 @@ class user_profile_fields_test extends core_reportbuilder_testcase { $this->getDataGenerator()->create_custom_profile_field([ 'shortname' => 'checkbox', 'name' => 'Checkbox field', 'datatype' => 'checkbox']); + // This field is available only to admins. $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, + 'visible' => PROFILE_VISIBLE_NONE]); $this->getDataGenerator()->create_custom_profile_field([ 'shortname' => 'menu', 'name' => 'Menu field', 'datatype' => 'menu', 'param1' => "Cat\nDog"]); @@ -80,55 +82,88 @@ class user_profile_fields_test extends core_reportbuilder_testcase { */ public function test_get_columns(): void { $this->resetAfterTest(); - - $userentity = new user(); - $useralias = $userentity->get_table_alias('user'); + $this->setAdminUser(); // Get pre-existing user profile fields. - $initialuserprofilefields = new user_profile_fields("$useralias.id", $userentity->get_entity_name()); - $initialcolumns = $initialuserprofilefields->get_columns(); - $initialcolumntitles = array_map(static function(column $column): string { - return $column->get_title(); - }, $initialcolumns); - $initialcolumntypes = array_map(static function(column $column): int { - return $column->get_type(); - }, $initialcolumns); + $userentity = new user(); + $initialcolumns = (new user_profile_fields( + $userentity->get_table_alias('user') . '.id', + $userentity->get_entity_name(), + ))->get_columns(); // Add new custom profile fields. $userprofilefields = $this->generate_userprofilefields(); - $columns = $userprofilefields->get_columns(); - // Columns count should be equal to start + 6. - $this->assertCount(count($initialcolumns) + 6, $columns); + // Ensure pre-existing fields are ignored in subsequent assertions. + $columns = array_slice($userprofilefields->get_columns(), count($initialcolumns)); + $this->assertCount(6, $columns); $this->assertContainsOnlyInstancesOf(column::class, $columns); - // Assert column titles. - $columntitles = array_map(static function(column $column): string { - return $column->get_title(); - }, $columns); - $expectedcolumntitles = array_merge($initialcolumntitles, [ + // Column titles. + $this->assertEquals([ 'Checkbox field', 'Date field', 'Menu field', 'MSN ID', 'Text field', 'Textarea field', - ]); - $this->assertEquals($expectedcolumntitles, $columntitles); + ], array_map( + fn(column $column): string => $column->get_title(), + $columns, + )); - // Assert column types. - $columntypes = array_map(static function(column $column): int { - return $column->get_type(); - }, $columns); - $expectedcolumntypes = array_merge($initialcolumntypes, [ + // Column types. + $this->assertEquals([ column::TYPE_BOOLEAN, column::TYPE_TIMESTAMP, column::TYPE_TEXT, column::TYPE_TEXT, column::TYPE_TEXT, column::TYPE_LONGTEXT, - ]); - $this->assertEquals($expectedcolumntypes, $columntypes); + ], array_map( + fn(column $column): int => $column->get_type(), + $columns, + )); + + // Column sortable. + $this->assertEquals([ + true, + true, + true, + true, + true, + false, + ], array_map( + fn(column $column): bool => $column->get_is_sortable(), + $columns, + )); + + // Column available. + $this->assertEquals([ + true, + true, + true, + true, + true, + true, + ], array_map( + fn(column $column): bool => $column->get_is_available(), + $columns, + )); + + // Column available, for non-privileged user. + $this->setUser(null); + $this->assertEquals([ + true, + false, + true, + true, + true, + true, + ], array_map( + fn(column $column): bool => $column->get_is_available(), + array_slice($userprofilefields->get_columns(), count($initialcolumns)), + )); } /** @@ -166,38 +201,62 @@ class user_profile_fields_test extends core_reportbuilder_testcase { */ public function test_get_filters(): void { $this->resetAfterTest(); - - $userentity = new user(); - $useralias = $userentity->get_table_alias('user'); + $this->setAdminUser(); // Get pre-existing user profile fields. - $initialuserprofilefields = new user_profile_fields("$useralias.id", $userentity->get_entity_name()); - $initialfilters = $initialuserprofilefields->get_filters(); - $initialfilterheaders = array_map(static function(filter $filter): string { - return $filter->get_header(); - }, $initialfilters); + $userentity = new user(); + $initialfilters = (new user_profile_fields( + $userentity->get_table_alias('user') . '.id', + $userentity->get_entity_name(), + ))->get_filters(); // Add new custom profile fields. $userprofilefields = $this->generate_userprofilefields(); - $filters = $userprofilefields->get_filters(); - // Filters count should be equal to start + 6. - $this->assertCount(count($initialfilters) + 6, $filters); + // Ensure pre-existing fields are ignored in subsequent assertions. + $filters = array_slice($userprofilefields->get_filters(), count($initialfilters)); + $this->assertCount(6, $filters); $this->assertContainsOnlyInstancesOf(filter::class, $filters); - // Assert filter headers. - $filterheaders = array_map(static function(filter $filter): string { - return $filter->get_header(); - }, $filters); - $expectedfilterheaders = array_merge($initialfilterheaders, [ + // Filter headers. + $this->assertEquals([ 'Checkbox field', 'Date field', 'Menu field', 'MSN ID', 'Text field', 'Textarea field', - ]); - $this->assertEquals($expectedfilterheaders, $filterheaders); + ], array_map( + fn(filter $filter): string => $filter->get_header(), + $filters, + )); + + // Filter available. + $this->assertEquals([ + true, + true, + true, + true, + true, + true, + ], array_map( + fn(filter $filter): bool => $filter->get_is_available(), + $filters, + )); + + // Filter available, for non-privileged user. + $this->setUser(null); + $this->assertEquals([ + true, + false, + true, + true, + true, + true, + ], array_map( + fn(filter $filter): bool => $filter->get_is_available(), + array_slice($userprofilefields->get_filters(), count($initialfilters)), + )); } /** @@ -205,6 +264,7 @@ class user_profile_fields_test extends core_reportbuilder_testcase { */ public function test_custom_report_content(): void { $this->resetAfterTest(); + $this->setAdminUser(); $userprofilefields = $this->generate_userprofilefields(); @@ -322,6 +382,7 @@ class user_profile_fields_test extends core_reportbuilder_testcase { */ public function test_custom_report_filter(string $filtername, array $filtervalues, string $expectmatchuser): void { $this->resetAfterTest(); + $this->setAdminUser(); $userprofilefields = $this->generate_userprofilefields();