From b9f2c35698fe199bbc42e66e07abba6627325b86 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Thu, 21 Mar 2024 13:24:25 +1100 Subject: [PATCH] issue #45: add support for cohort custom fields --- classes/condition_base.php | 5 + .../condition/cohort_field.php | 180 +++++++++++++++--- .../condition/fields_trait.php | 8 +- .../condition/user_custom_profile.php | 4 +- .../condition/user_profile.php | 4 +- lang/en/tool_dynamic_cohorts.php | 3 + .../condition/cohort_field_test.php | 156 +++++++++++++-- 7 files changed, 313 insertions(+), 47 deletions(-) diff --git a/classes/condition_base.php b/classes/condition_base.php index 7b1cd83..a5a1ff2 100644 --- a/classes/condition_base.php +++ b/classes/condition_base.php @@ -35,6 +35,11 @@ abstract class condition_base { */ public const FIELD_DATA_TYPE_MENU = 'menu'; + /** + * Value for select field types. + */ + public const FIELD_DATA_TYPE_SELECT = 'select'; + /** * Value for checkbox field types. */ diff --git a/classes/local/tool_dynamic_cohorts/condition/cohort_field.php b/classes/local/tool_dynamic_cohorts/condition/cohort_field.php index 8583ef6..cf3e60f 100644 --- a/classes/local/tool_dynamic_cohorts/condition/cohort_field.php +++ b/classes/local/tool_dynamic_cohorts/condition/cohort_field.php @@ -16,6 +16,7 @@ namespace tool_dynamic_cohorts\local\tool_dynamic_cohorts\condition; +use coding_exception; use core_course_category; use context_system; use context_coursecat; @@ -78,6 +79,15 @@ protected function get_cohort_operators(): array { ]; } + /** + * Get a list of supported custom fields. + * + * @return array + */ + protected function get_supported_custom_fields(): array { + return [self::FIELD_DATA_TYPE_TEXT, self::FIELD_DATA_TYPE_SELECT, self::FIELD_DATA_TYPE_CHECKBOX]; + } + /** * Returns a list of all fields with extra data (shortname, name, datatype, param1 and type). * @@ -118,6 +128,38 @@ protected function get_fields_info(): array { } } + // Workout custom fields if they are available. + if (class_exists(\core_cohort\customfield\cohort_handler::class)) { + $handler = \core_cohort\customfield\cohort_handler::create(); + + foreach ($handler->get_fields() as $customfield) { + + if (!in_array($customfield->get('type'), $this->get_supported_custom_fields())) { + continue; + } + + $shortname = self::CUSTOM_FIELD_PREFIX . $customfield->get('shortname'); + $fields[$shortname] = new \stdClass(); + $fields[$shortname]->name = $customfield->get_formatted_name(); + $fields[$shortname]->shortname = $shortname; + $fields[$shortname]->datatype = $customfield->get('type'); + + switch ($fields[$shortname]->datatype) { + case self::FIELD_DATA_TYPE_SELECT: + $fields[$shortname]->param1 = $customfield->get_options(); + break; + case self::FIELD_DATA_TYPE_TEXT: + $fields[$shortname]->paramtype = PARAM_TEXT; + break; + case self::FIELD_DATA_TYPE_CHECKBOX: + $fields[$shortname]->param1 = array_combine([0, 1], [get_string('no'), get_string('yes')]); + break; + default: + throw new coding_exception('Invalid field type ' . $fields[$shortname]->datatype); + } + } + } + return $fields; } @@ -161,12 +203,14 @@ public function config_form_add(\MoodleQuickForm $mform): void { $group = []; $group[] = $mform->createElement('select', $this->get_form_field(), '', $options); + $includemissing = []; foreach ($fields as $shortname => $field) { switch ($field->datatype) { case self::FIELD_DATA_TYPE_TEXT: $this->add_text_field($mform, $group, $field, $shortname); break; + case self::FIELD_DATA_TYPE_SELECT: case self::FIELD_DATA_TYPE_MENU: $this->add_menu_field($mform, $group, $field, $shortname); break; @@ -174,11 +218,30 @@ public function config_form_add(\MoodleQuickForm $mform): void { $this->add_checkbox_field($mform, $group, $field, $shortname); break; default: - throw new \coding_exception('Invalid field type ' . $field->datatype); + throw new coding_exception('Invalid field type ' . $field->datatype); + } + + // Create "include missing data" checkbox for each of custom fields. + if ($this->is_custom_field($shortname)) { + $name = $shortname . '_include_missing_data'; + $includemissing[$name] = $mform->createElement( + 'checkbox', + $name, + '', + get_string('cf_include_missing_data', 'tool_dynamic_cohorts') + ); + + $mform->hideIf($name, self::get_form_field(), 'neq', $shortname); } } $mform->addGroup($group, 'fieldgroup', get_string('cohortswith', 'tool_dynamic_cohorts'), '', false); + + // Add "include missing data" checkbox. + foreach ($includemissing as $fieldname => $element) { + $mform->addElement($element); + $mform->addHelpButton($fieldname, 'cf_include_missing_data', 'tool_dynamic_cohorts'); + } } /** @@ -273,8 +336,8 @@ public function get_config_description(): string { return ''; } - $datatype = $this->get_fields_info()[$fieldname]->datatype; - $fieldoperator = $this->get_operator_text($datatype); + $fieldinfo = $this->get_fields_info()[$fieldname]; + $fieldoperator = $this->get_operator_text($fieldinfo->datatype); $fieldvalue = $this->get_field_value(); if ($fieldname == 'contextid') { @@ -285,66 +348,137 @@ public function get_config_description(): string { $fieldvalue = null; } - return get_string('condition:cohort_field_description', 'tool_dynamic_cohorts', (object)[ + if ($fieldinfo->datatype === self::FIELD_DATA_TYPE_SELECT) { + $fieldvalue = $fieldinfo->param1[$fieldvalue]; + } + + $fieldname = $fieldinfo->name; + + $description = get_string('condition:cohort_field_description', 'tool_dynamic_cohorts', (object)[ 'operator' => $cohortoperator, 'field' => $fieldname, 'fieldoperator' => $fieldoperator, 'fieldvalue' => $fieldvalue, ]); + + if ($this->should_include_missing_data()) { + $description .= ' ' . get_string('cf_includingmissingdatadesc', 'tool_dynamic_cohorts'); + } + + return $description; + } + + /** + * Check if a given field is a custom field. + * + * @param string $fieldname Field name. + * @return bool + */ + protected function is_custom_field(string $fieldname): bool { + return strpos($fieldname, self::CUSTOM_FIELD_PREFIX) === 0; + } + + /** + * Check if we should include missing data from user_info_data table. + * + * @return bool + */ + protected function should_include_missing_data(): bool { + return !empty($this->get_config_data()[$this->get_field_name() . '_include_missing_data']); } /** * Gets SQL data for building SQL. * + * We are getting all members for cohorts that match configured condition of + * one of the fields from {cohort} table or a custom field that stores value + * in {customfield_data} table in 'value' column. + * * @return condition_sql */ public function get_sql(): condition_sql { $result = new condition_sql('', '1=0', []); if (!$this->is_broken()) { - $innertable = condition_sql::generate_table_alias(); - $outertable = condition_sql::generate_table_alias(); - $configuredfield = $this->get_field_name(); $datatype = $this->get_fields_info()[$configuredfield]->datatype; - $ud = condition_sql::generate_table_alias(); + $fieldstable = condition_sql::generate_table_alias(); - $cohortsqldata = new condition_sql('', '1=0', []); + // For custom fields target DB column "value" is from {customfield_data}. + // For regular fields target DB column is from {cohort} table, so it's same as configured field. + $dbcolumn = !$this->is_custom_field($configuredfield) ? $configuredfield : 'value'; switch ($datatype) { case self::FIELD_DATA_TYPE_TEXT: - $cohortsqldata = $this->get_text_sql_data($ud, $configuredfield); + $fieldsqldata = $this->get_text_sql($fieldstable, $dbcolumn); break; case self::FIELD_DATA_TYPE_CHECKBOX: case self::FIELD_DATA_TYPE_MENU: - $cohortsqldata = $this->get_menu_sql_data($ud, $configuredfield); + case self::FIELD_DATA_TYPE_SELECT: + $fieldsqldata = $this->get_menu_sql($fieldstable, $dbcolumn); break; + default: + throw new coding_exception('Invalid field type ' . $datatype); } // Including only cohorts with configured fields. - $cohortwhere = $cohortsqldata->get_where(); - $cohortjoin = $cohortsqldata->get_join(); - $cohortsql = "SELECT $ud.id FROM {cohort} $ud $cohortjoin WHERE $cohortwhere"; - $params = $cohortsqldata->get_params(); + $fieldwhere = $fieldsqldata->get_where(); + $fieldjoin = $fieldsqldata->get_join(); + $params = $fieldsqldata->get_params(); + + if ($this->is_custom_field($configuredfield)) { + $cohorttbl = condition_sql::generate_table_alias(); + $fieldtbl = condition_sql::generate_table_alias(); + $fieldcategorytbl = condition_sql::generate_table_alias(); + $shortnameparam = condition_sql::generate_param_alias(); + + $params[$shortnameparam] = str_replace(self::CUSTOM_FIELD_PREFIX, '', $configuredfield); + + $cohortwhere = "$fieldcategorytbl.component = 'core_cohort' + AND $fieldcategorytbl.area = 'cohort' + AND $fieldtbl.shortname = :$shortnameparam + AND $fieldwhere"; + + if ($this->should_include_missing_data()) { + $cohortwhere .= " OR $fieldstable.instanceid IS NULL"; + } + + $cohortsql = "SELECT $cohorttbl.id + FROM {cohort} $cohorttbl + LEFT JOIN {customfield_data} $fieldstable ON $fieldstable.instanceid = $cohorttbl.id + LEFT JOIN {customfield_field} $fieldtbl ON $fieldstable.fieldid = $fieldtbl.id + LEFT JOIN {customfield_category} $fieldcategorytbl ON $fieldcategorytbl.id = $fieldtbl.categoryid + $fieldjoin + WHERE $cohortwhere"; + } else { + $cohorttbl = $fieldstable; + $cohortsql = "SELECT $cohorttbl.id + FROM {cohort} $cohorttbl + $fieldjoin + WHERE $fieldwhere"; + } - // Exclude cohort that managed by a parent rule. + // Exclude cohort that managed by a related rule. $rule = $this->get_rule(); if ($rule) { $selectedcohortparam = condition_sql::generate_param_alias(); - $cohortsql .= "AND $ud.id <> :$selectedcohortparam"; + $cohortsql .= " AND $cohorttbl.id <> :$selectedcohortparam"; $params[$selectedcohortparam] = $rule->get('cohortid'); } + $cohortmemberstbl = condition_sql::generate_table_alias(); + $outertbl = condition_sql::generate_table_alias(); + // Are we getting members? $needmembers = $this->get_cohort_operator_value() == self::OPERATOR_IS_MEMBER_OF; // Select all users that are members or not members of selected cohorts depending on selected operator. - $join = "LEFT JOIN (SELECT {$innertable}.userid - FROM {cohort_members} $innertable - WHERE {$innertable}.cohortid IN ({$cohortsql})) {$outertable} - ON u.id = {$outertable}.userid"; + $join = "LEFT JOIN (SELECT {$cohortmemberstbl}.userid + FROM {cohort_members} $cohortmemberstbl + WHERE {$cohortmemberstbl}.cohortid IN ({$cohortsql})) {$outertbl} + ON u.id = {$outertbl}.userid"; - $where = $needmembers ? "$outertable.userid is NOT NULL" : "$outertable.userid is NULL"; - $result = new condition_sql($join, $where, $params); + $cohortwhere = $needmembers ? "$outertbl.userid is NOT NULL" : "$outertbl.userid is NULL"; + $result = new condition_sql($join, $cohortwhere, $params); } return $result; diff --git a/classes/local/tool_dynamic_cohorts/condition/fields_trait.php b/classes/local/tool_dynamic_cohorts/condition/fields_trait.php index 1158069..0cee639 100644 --- a/classes/local/tool_dynamic_cohorts/condition/fields_trait.php +++ b/classes/local/tool_dynamic_cohorts/condition/fields_trait.php @@ -28,7 +28,7 @@ trait fields_trait { /** - * Gets an list of comparison operators for text fields. + * Gets a list of comparison operators for text fields. * * @return array A list of operators. */ @@ -46,7 +46,7 @@ protected function get_text_operators() : array { } /** - * Gets an list of comparison operators for menu fields. + * Gets a list of comparison operators for menu fields. * * @return array A list of operators. */ @@ -184,7 +184,7 @@ protected function add_checkbox_field(\MoodleQuickForm $mform, array &$group, \s * @param string $fieldname Field name. * @return condition_sql */ - protected function get_text_sql_data(string $tablealias, string $fieldname): condition_sql { + protected function get_text_sql(string $tablealias, string $fieldname): condition_sql { global $DB; $fieldvalue = $this->get_field_value(); @@ -247,7 +247,7 @@ protected function get_text_sql_data(string $tablealias, string $fieldname): con * @param string $fieldname Field name. * @return condition_sql */ - protected function get_menu_sql_data(string $tablealias, string $fieldname): condition_sql { + protected function get_menu_sql(string $tablealias, string $fieldname): condition_sql { global $DB; $fieldvalue = $this->get_field_value(); diff --git a/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php b/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php index 1d41d54..34e0594 100644 --- a/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php +++ b/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php @@ -176,11 +176,11 @@ public function get_sql(): condition_sql { switch ($datatype) { case self::FIELD_DATA_TYPE_TEXT: - $result = $this->get_text_sql_data($ud, 'data'); + $result = $this->get_text_sql($ud, 'data'); break; case self::FIELD_DATA_TYPE_CHECKBOX: case self::FIELD_DATA_TYPE_MENU: - $result = $this->get_menu_sql_data($ud, 'data'); + $result = $this->get_menu_sql($ud, 'data'); break; } diff --git a/classes/local/tool_dynamic_cohorts/condition/user_profile.php b/classes/local/tool_dynamic_cohorts/condition/user_profile.php index 953bb1e..5142bd1 100644 --- a/classes/local/tool_dynamic_cohorts/condition/user_profile.php +++ b/classes/local/tool_dynamic_cohorts/condition/user_profile.php @@ -222,10 +222,10 @@ public function get_sql(): condition_sql { switch ($datatype) { case self::FIELD_DATA_TYPE_TEXT: - $result = $this->get_text_sql_data('u', $this->get_field_name()); + $result = $this->get_text_sql('u', $this->get_field_name()); break; case self::FIELD_DATA_TYPE_MENU: - $result = $this->get_menu_sql_data('u', $this->get_field_name()); + $result = $this->get_menu_sql('u', $this->get_field_name()); break; } diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index ac52144..6854e88 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -51,6 +51,9 @@ $string['condition:cohort_field_description'] = 'A user {$a->operator} cohorts with field \'{$a->field}\' {$a->fieldoperator} {$a->fieldvalue}'; $string['condition:user_profile'] = 'User standard profile field'; $string['condition:user_custom_profile'] = 'User custom profile field'; +$string['cf_include_missing_data'] = 'Include cohorts with missing data.'; +$string['cf_include_missing_data_help'] = 'Cohorts may not have a custom field data set yet. This option includes those cohorts in the final result.'; +$string['cf_includingmissingdatadesc'] = '(including cohorts with missing data)'; $string['delete_confirm'] = 'Are you sure you want to delete rule {$a}?'; $string['delete_confirm_condition'] = 'Are you sure you want to delete this condition?'; $string['delete_rule'] = 'Delete rule'; diff --git a/tests/local/tool_dynamic_cohorts/condition/cohort_field_test.php b/tests/local/tool_dynamic_cohorts/condition/cohort_field_test.php index 758f1f8..855bece 100644 --- a/tests/local/tool_dynamic_cohorts/condition/cohort_field_test.php +++ b/tests/local/tool_dynamic_cohorts/condition/cohort_field_test.php @@ -91,14 +91,14 @@ public function test_set_and_get_configdata() { */ public function config_description_data_provider(): array { return [ - [cohort_field::TEXT_CONTAINS, 'A user is not member of cohorts with field \'theme\' contains 123'], - [cohort_field::TEXT_DOES_NOT_CONTAIN, 'A user is not member of cohorts with field \'theme\' doesn\'t contain 123'], - [cohort_field::TEXT_IS_EQUAL_TO, 'A user is not member of cohorts with field \'theme\' is equal to 123'], - [cohort_field::TEXT_IS_NOT_EQUAL_TO, 'A user is not member of cohorts with field \'theme\' isn\'t equal to 123'], - [cohort_field::TEXT_STARTS_WITH, 'A user is not member of cohorts with field \'theme\' starts with 123'], - [cohort_field::TEXT_ENDS_WITH, 'A user is not member of cohorts with field \'theme\' ends with 123'], - [cohort_field::TEXT_IS_EMPTY, 'A user is not member of cohorts with field \'theme\' is empty '], - [cohort_field::TEXT_IS_NOT_EMPTY, 'A user is not member of cohorts with field \'theme\' is not empty '], + [condition_base::TEXT_CONTAINS, 'A user is not member of cohorts with field \'Theme\' contains 123'], + [condition_base::TEXT_DOES_NOT_CONTAIN, 'A user is not member of cohorts with field \'Theme\' doesn\'t contain 123'], + [condition_base::TEXT_IS_EQUAL_TO, 'A user is not member of cohorts with field \'Theme\' is equal to 123'], + [condition_base::TEXT_IS_NOT_EQUAL_TO, 'A user is not member of cohorts with field \'Theme\' isn\'t equal to 123'], + [condition_base::TEXT_STARTS_WITH, 'A user is not member of cohorts with field \'Theme\' starts with 123'], + [condition_base::TEXT_ENDS_WITH, 'A user is not member of cohorts with field \'Theme\' ends with 123'], + [condition_base::TEXT_IS_EMPTY, 'A user is not member of cohorts with field \'Theme\' is empty '], + [condition_base::TEXT_IS_NOT_EMPTY, 'A user is not member of cohorts with field \'Theme\' is not empty '], ]; } @@ -132,12 +132,12 @@ public function test_config_description_context_id() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'contextid', - 'contextid_operator' => cohort_field::TEXT_IS_EQUAL_TO, + 'contextid_operator' => condition_base::TEXT_IS_EQUAL_TO, 'contextid_value' => $catcontext->id, ]); $this->assertSame( - 'A user is member of cohorts with field \'contextid\' is equal to ' . $coursecategory->name, + 'A user is member of cohorts with field \'Context\' is equal to ' . $coursecategory->name, $condition->get_config_description() ); } @@ -173,7 +173,7 @@ public function test_is_broken() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'contextid', - 'contextid_operator' => cohort_field::TEXT_IS_EQUAL_TO, + 'contextid_operator' => condition_base::TEXT_IS_EQUAL_TO, 'contextid_value' => 7777, ]); $this->assertTrue($condition->is_broken()); @@ -181,7 +181,7 @@ public function test_is_broken() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'name', - 'name_operator' => cohort_field::TEXT_IS_EMPTY, + 'name_operator' => condition_base::TEXT_IS_EMPTY, 'name_value' => '', ]); $this->assertFalse($condition->is_broken()); @@ -189,7 +189,7 @@ public function test_is_broken() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'name', - 'name_operator' => cohort_field::TEXT_IS_NOT_EMPTY, + 'name_operator' => condition_base::TEXT_IS_NOT_EMPTY, 'name_value' => '', ]); $this->assertFalse($condition->is_broken()); @@ -197,7 +197,7 @@ public function test_is_broken() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'name', - 'name_operator' => cohort_field::TEXT_IS_EQUAL_TO, + 'name_operator' => condition_base::TEXT_IS_EQUAL_TO, 'name_value' => '', ]); $this->assertTrue($condition->is_broken()); @@ -205,7 +205,7 @@ public function test_is_broken() { $condition = $this->get_condition([ 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, 'cohort_field_field' => 'notexists', - 'notexists_operator' => cohort_field::TEXT_IS_EQUAL_TO, + 'notexists_operator' => condition_base::TEXT_IS_EQUAL_TO, 'notexists_value' => '', ]); $this->assertTrue($condition->is_broken()); @@ -214,7 +214,7 @@ public function test_is_broken() { /** * Test getting SQL. */ - public function test_get_sql_data() { + public function test_get_sql_data_standard_fields() { global $DB; $this->resetAfterTest(); @@ -267,6 +267,130 @@ public function test_get_sql_data() { $this->assertCount($totalusers, $DB->get_records_sql($sql, $result->get_params())); } + /** + * Create Cohort custom field for testing. + * + * @return \core_customfield\field_controller + */ + protected function create_cohort_custom_field(): \core_customfield\field_controller { + $fieldcategory = self::getDataGenerator()->create_custom_field_category([ + 'component' => 'core_cohort', + 'area' => 'cohort', + 'name' => 'Other fields', + ]); + + return self::getDataGenerator()->create_custom_field([ + 'shortname' => 'testfield1', + 'name' => 'Custom field', + 'type' => 'text', + 'categoryid' => $fieldcategory->get('id'), + ]); + } + + /** + * Test getting config description when using a custom field. + */ + public function test_config_description_custom_field() { + if (!class_exists(\core_cohort\customfield\cohort_handler::class)) { + $this->markTestSkipped(); + } + + $this->resetAfterTest(); + $this->create_cohort_custom_field(); + + $condition = $this->get_condition([ + 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, + 'cohort_field_field' => cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_operator' => condition_base::TEXT_IS_EQUAL_TO, + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_value' => 'Test value', + ]); + + $this->assertSame( + 'A user is member of cohorts with field \'Custom field\' is equal to Test value', + $condition->get_config_description() + ); + } + + /** + * Test getting SQL. + */ + public function test_get_sql_data_custom_fields() { + global $DB; + + if (!class_exists(\core_cohort\customfield\cohort_handler::class)) { + $this->markTestSkipped(); + } + + $this->resetAfterTest(); + + // We need admin to be able to add custom fields data for cohorts. + $this->setAdminUser(); + + $this->create_cohort_custom_field(); + + $cohort1 = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']); + $cohort2 = $this->getDataGenerator()->create_cohort(); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $user3 = $this->getDataGenerator()->create_user(); + + cohort_add_member($cohort1->id, $user1->id); + cohort_add_member($cohort1->id, $user2->id); + cohort_add_member($cohort2->id, $user3->id); + + $totalusers = $DB->count_records('user'); + + // User 1 and user 2 as they are members of cohort 1. + $condition = $this->get_condition([ + 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, + 'cohort_field_field' => cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_operator' => condition_base::TEXT_IS_EQUAL_TO, + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_value' => 'Test value 1', + ]); + + $result = $condition->get_sql(); + $sql = "SELECT u.id FROM {user} u {$result->get_join()} WHERE {$result->get_where()}"; + $this->assertCount(2, $DB->get_records_sql($sql, $result->get_params())); + + // Everyone except user 1 and user 2 as they are member of cohort 1. + $condition = $this->get_condition([ + 'cohort_field_operator' => cohort_field::OPERATOR_IS_NOT_MEMBER_OF, + 'cohort_field_field' => cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_operator' => condition_base::TEXT_IS_EQUAL_TO, + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_value' => 'Test value 1', + ]); + + $result = $condition->get_sql(); + $sql = "SELECT u.id FROM {user} u {$result->get_join()} WHERE {$result->get_where()}"; + $this->assertCount($totalusers - 2, $DB->get_records_sql($sql, $result->get_params())); + + // Everyone as cohort is empty. + $condition = $this->get_condition([ + 'cohort_field_operator' => cohort_field::OPERATOR_IS_NOT_MEMBER_OF, + 'cohort_field_field' => cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_operator' => condition_base::TEXT_IS_EQUAL_TO, + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_value' => 'Test value 2', + ]); + + $result = $condition->get_sql(); + $sql = "SELECT u.id FROM {user} u {$result->get_join()} WHERE {$result->get_where()}"; + $this->assertCount($totalusers, $DB->get_records_sql($sql, $result->get_params())); + + // User 1, user 2 and user 3 as they are members of cohort 1 and cohort 2 (this one is with missing custom field data). + $condition = $this->get_condition([ + 'cohort_field_operator' => cohort_field::OPERATOR_IS_MEMBER_OF, + 'cohort_field_field' => cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_operator' => condition_base::TEXT_IS_EQUAL_TO, + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_value' => 'Test value 1', + cohort_field::CUSTOM_FIELD_PREFIX . 'testfield1_include_missing_data' => '1', + ]); + + $result = $condition->get_sql(); + $sql = "SELECT u.id FROM {user} u {$result->get_join()} WHERE {$result->get_where()}"; + $this->assertCount(3, $DB->get_records_sql($sql, $result->get_params())); + } + /** * Test events that the condition is listening to. */