diff --git a/classes/local/tool_dynamic_cohorts/condition/auth_method.php b/classes/local/tool_dynamic_cohorts/condition/auth_method.php index 23b81cf..2b7d3c8 100644 --- a/classes/local/tool_dynamic_cohorts/condition/auth_method.php +++ b/classes/local/tool_dynamic_cohorts/condition/auth_method.php @@ -29,6 +29,15 @@ */ class auth_method extends user_profile { + /** + * Return field name in the condition config form. + * + * @return string + */ + protected static function get_form_field(): string { + return 'authmethod'; + } + /** * Condition name. * @@ -46,8 +55,8 @@ public function get_name(): string { public function config_form_add(\MoodleQuickForm $mform): void { $fields = $this->get_fields_info(); - $mform->addElement('hidden', self::FIELD_NAME, 'auth'); - $mform->setType(self::FIELD_NAME, PARAM_ALPHA); + $mform->addElement('hidden', static::get_form_field(), 'auth'); + $mform->setType(static::get_form_field(), PARAM_ALPHA); $group = []; $this->add_menu_field($mform, $group, $fields['auth'], 'auth'); 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 1abaea3..9656b80 100644 --- a/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php +++ b/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php @@ -16,6 +16,7 @@ namespace tool_dynamic_cohorts\local\tool_dynamic_cohorts\condition; +use coding_exception; use tool_dynamic_cohorts\condition_sql; /** @@ -26,6 +27,7 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class user_custom_profile extends user_profile { + /** * Field name to store include missing data option, */ @@ -34,7 +36,12 @@ class user_custom_profile extends user_profile { /** * A list of supported custom profile fields. */ - protected const SUPPORTED_CUSTOM_FIELDS = ['text', 'menu']; + protected const SUPPORTED_CUSTOM_FIELDS = ['text', 'menu', 'checkbox']; + + /** + * Value for checkbox field types. + */ + public const FIELD_DATA_TYPE_CHECKBOX = 'checkbox'; /** * Custom field prefix. @@ -51,7 +58,7 @@ public function get_name(): string { } /** - * Returns a list of all fields with extra data (shortname, name, datatype, param1 and type). + * Returns a list of all fields with extra data (shortname, name, datatype and param1). * * @return \stdClass[] */ @@ -70,11 +77,19 @@ protected function get_fields_info(): array { $field = (object)array_intersect_key((array)$customfield->field, ['shortname' => 1, 'name' => 1, 'datatype' => 1, 'param1' => 1]); - if ($field->datatype == self::FIELD_DATA_TYPE_MENU) { - $options = explode("\n", $field->param1); - $field->param1 = array_combine($options, $options); - } else if ($field->datatype == 'text') { - $field->paramtype = PARAM_TEXT; + switch ($field->datatype) { + case self::FIELD_DATA_TYPE_MENU: + $options = explode("\n", $field->param1); + $field->param1 = array_combine($options, $options); + break; + case self::FIELD_DATA_TYPE_TEXT: + $field->paramtype = PARAM_TEXT; + break; + case self::FIELD_DATA_TYPE_CHECKBOX: + $field->param1 = array_combine([0, 1], [get_string('no'), get_string('yes')]); + break; + default: + throw new coding_exception('Invalid field type ' . $field->datatype); } $shortname = self::FIELD_PREFIX . $field->shortname; @@ -90,7 +105,31 @@ protected function get_fields_info(): array { * @param \MoodleQuickForm $mform */ public function config_form_add(\MoodleQuickForm $mform): void { - parent::config_form_add($mform); + $options = [0 => get_string('select')]; + + $fields = $this->get_fields_info(); + foreach ($fields as $shortname => $field) { + $options[$shortname] = $field->name; + } + + $group = []; + $group[] = $mform->createElement('select', static::get_form_field(), '', $options); + + 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_MENU: + $this->add_menu_field($mform, $group, $field, $shortname); + break; + case self::FIELD_DATA_TYPE_CHECKBOX: + $this->add_checkbox_field($mform, $group, $field, $shortname); + break; + } + } + + $mform->addGroup($group, 'profilefieldgroup', get_string('profilefield', 'tool_dynamic_cohorts'), '', false); $mform->addElement( 'checkbox', @@ -102,6 +141,23 @@ public function config_form_add(\MoodleQuickForm $mform): void { $mform->addHelpButton(self::INCLUDE_MISSING_DATA_FIELD_NAME, self::INCLUDE_MISSING_DATA_FIELD_NAME, 'tool_dynamic_cohorts'); } + /** + * Adds a check box field to the form. + * + * @param \MoodleQuickForm $mform Form to add the field to. + * @param array $group A group to add the field to. + * @param \stdClass $field Field info. + * @param string $shortname A field shortname. + */ + protected function add_checkbox_field(\MoodleQuickForm $mform, array &$group, \stdClass $field, string $shortname): void { + $options = (array) $field->param1; + + $elements = []; + $elements[] = $mform->createElement('hidden', $shortname . '_operator', self::TEXT_IS_EQUAL_TO); + $elements[] = $mform->createElement('select', $shortname . '_value', $field->name, $options); + $group[] = $mform->createElement('group', $shortname, '', $elements, '', false); + $mform->hideIf($shortname, static::get_form_field(), 'neq', $shortname); + } /** * Gets required config data from submitted condition form data. * @@ -121,24 +177,7 @@ public static function retrieve_config_data(\stdClass $formdata): array { * @return bool */ protected function should_include_missing_data(): bool { - if (in_array($this->get_operator_value(), $this->missing_data_operators())) { - return !empty($this->get_config_data()[self::INCLUDE_MISSING_DATA_FIELD_NAME]); - } - - return false; - } - - /** - * A list of operators that getting missing data does make sense for. - * - * @return array - */ - protected function missing_data_operators(): array { - return [ - self::TEXT_DOES_NOT_CONTAIN, - self::TEXT_IS_NOT_EQUAL_TO, - self::TEXT_IS_EMPTY, - ]; + return !empty($this->get_config_data()[self::INCLUDE_MISSING_DATA_FIELD_NAME]); } /** @@ -157,6 +196,7 @@ public function get_sql(): condition_sql { case self::FIELD_DATA_TYPE_TEXT: $result = $this->get_text_sql_data($ud, 'data'); break; + case self::FIELD_DATA_TYPE_CHECKBOX: case self::FIELD_DATA_TYPE_MENU: $result = $this->get_menu_sql_data($ud, 'data'); break; @@ -191,6 +231,26 @@ public function get_sql(): condition_sql { return $result; } + /** + * Returns a value of the configured field. + * + * @return string|null + */ + protected function get_field_value(): ?string { + $fieldvalue = parent::get_field_value(); + + // A special case for checkbox field. + $fieldname = $this->get_field_name(); + if (!empty($fieldname) && !empty($this->get_fields_info()[$fieldname])) { + $datatype = $this->get_fields_info()[$fieldname]->datatype; + if ($datatype == self::FIELD_DATA_TYPE_CHECKBOX) { + $fieldvalue = empty($fieldvalue) ? get_string('no') : get_string('yes'); + } + } + + return $fieldvalue; + } + /** * Human-readable description of the configured condition. * diff --git a/classes/local/tool_dynamic_cohorts/condition/user_profile.php b/classes/local/tool_dynamic_cohorts/condition/user_profile.php index dbdaaa2..6999280 100644 --- a/classes/local/tool_dynamic_cohorts/condition/user_profile.php +++ b/classes/local/tool_dynamic_cohorts/condition/user_profile.php @@ -20,6 +20,7 @@ use tool_dynamic_cohorts\condition_sql; use core_user; use core_plugin_manager; +use coding_exception; /** * Condition using standard user profile. @@ -30,11 +31,6 @@ */ class user_profile extends condition_base { - /** - * Base field nname. - */ - public const FIELD_NAME = 'profilefield'; - /** * Value for text field types. */ @@ -91,6 +87,15 @@ class user_profile extends condition_base { protected const SUPPORTED_STANDARD_FIELDS = ['auth', 'firstname', 'lastname', 'username', 'email', 'idnumber', 'city', 'country', 'institution', 'department']; + /** + * Return field name in the condition config form. + * + * @return string + */ + protected static function get_form_field(): string { + return 'profilefield'; + } + /** * Condition name. * @@ -114,16 +119,18 @@ public function config_form_add(\MoodleQuickForm $mform): void { } $group = []; - $group[] = $mform->createElement('select', self::FIELD_NAME, '', $options); + $group[] = $mform->createElement('select', static::get_form_field(), '', $options); 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_MENU: + case self::FIELD_DATA_TYPE_MENU: $this->add_menu_field($mform, $group, $field, $shortname); break; + default: + throw new coding_exception('Invalid field type ' . $field->datatype); } } @@ -140,13 +147,13 @@ public function config_form_validate(array $data): array { $errors = []; $fields = $this->get_fields_info(); - if (empty($data[self::FIELD_NAME]) || !isset($data[self::FIELD_NAME]) || !isset($fields[$data[self::FIELD_NAME]])) { + if (empty($data[static::get_form_field()]) || !isset($fields[$data[static::get_form_field()]])) { $errors['profilefieldgroup'] = get_string('pleaseselectfield', 'tool_dynamic_cohorts'); } - $fieldvalue = $data[self::FIELD_NAME] . '_value'; - $operator = $data[self::FIELD_NAME] . '_operator'; - $datatype = $fields[$data[self::FIELD_NAME]]->datatype ?? ''; + $fieldvalue = $data[static::get_form_field()] . '_value'; + $operator = $data[static::get_form_field()] . '_operator'; + $datatype = $fields[$data[static::get_form_field()]]->datatype ?? ''; if (empty($data[$fieldvalue])) { if ($datatype == 'text' && !in_array($data[$operator], [self::TEXT_IS_EMPTY, self::TEXT_IS_NOT_EMPTY])) { @@ -165,12 +172,12 @@ public function config_form_validate(array $data): array { */ public static function retrieve_config_data(\stdClass $formdata): array { $configdata = parent::retrieve_config_data($formdata); - $fieldname = $configdata[self::FIELD_NAME]; + $fieldname = $configdata[static::get_form_field()]; $data = []; // Get field name itself. - $data[self::FIELD_NAME] = $fieldname; + $data[static::get_form_field()] = $fieldname; // Only get values related to the selected field name, e.g firstname_operator, firstname_value. foreach ($configdata as $key => $value) { @@ -262,7 +269,7 @@ protected function add_text_field(\MoodleQuickForm $mform, array &$group, \stdCl $mform->hideIf($shortname . '_value', $shortname . '_operator', 'in', self::TEXT_IS_EMPTY . '|' . self::TEXT_IS_NOT_EMPTY); $group[] = $mform->createElement('group', $shortname, '', $elements, '', false); - $mform->hideIf($shortname, self::FIELD_NAME, 'neq', $shortname); + $mform->hideIf($shortname, static::get_form_field(), 'neq', $shortname); } /** @@ -282,7 +289,7 @@ protected function add_menu_field(\MoodleQuickForm $mform, array &$group, \stdCl $mform->hideIf($shortname . '_value', $shortname . '_operator', 'in', self::TEXT_IS_EMPTY . '|' . self::TEXT_IS_NOT_EMPTY); $group[] = $mform->createElement('group', $shortname, '', $elements, '', false); - $mform->hideIf($shortname, self::FIELD_NAME, 'neq', $shortname); + $mform->hideIf($shortname, static::get_form_field(), 'neq', $shortname); } /** @@ -291,7 +298,7 @@ protected function add_menu_field(\MoodleQuickForm $mform, array &$group, \stdCl * @return string */ protected function get_field_name(): string { - return $this->get_config_data()[self::FIELD_NAME]; + return $this->get_config_data()[static::get_form_field()]; } /** @@ -349,7 +356,7 @@ protected function get_operator_text(string $fielddatatype): string { } /** - * Human readable description of the configured condition. + * Human-readable description of the configured condition. * * @return string */ diff --git a/index.php b/index.php index ca0c743..091d199 100644 --- a/index.php +++ b/index.php @@ -36,7 +36,7 @@ $editurl = new moodle_url('/admin/tool/dynamic_cohorts/edit.php'); foreach (rule::get_records() as $rule) { - if ($rule->is_broken(true)) { + if ($rule->is_broken()) { notification::warning(get_string('brokenruleswarning', 'tool_dynamic_cohorts')); break; } diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 68cacc1..0c47fd7 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -68,6 +68,7 @@ $string['event:ruledeleted'] = 'Rule deleted'; $string['includingmissingdatadesc'] = '(including users with missing data)'; $string['includeusersmissingdata'] = 'include users with missing data'; +$string['include_missing_data'] = 'Include users with missing data.'; $string['include_missing_data_help'] = 'Some users may not have a custom field data set yet. This option includes those user in the final result.'; $string['invalidfieldvalue'] = 'Invalid field value'; $string['ismemberof'] = 'is member of'; diff --git a/tests/local/tool_dynamic_cohorts/condition/user_custom_profile_test.php b/tests/local/tool_dynamic_cohorts/condition/user_custom_profile_test.php index 485a66f..564297d 100644 --- a/tests/local/tool_dynamic_cohorts/condition/user_custom_profile_test.php +++ b/tests/local/tool_dynamic_cohorts/condition/user_custom_profile_test.php @@ -150,14 +150,14 @@ public function test_set_and_get_configdata() { */ public function config_description_data_provider(): array { return [ - [user_profile::TEXT_CONTAINS, 'Test field1 contains 123', false], + [user_profile::TEXT_CONTAINS, 'Test field1 contains 123', true], [user_profile::TEXT_DOES_NOT_CONTAIN, 'Test field1 doesn\'t contain 123', true], - [user_profile::TEXT_IS_EQUAL_TO, 'Test field1 is equal to 123', false], + [user_profile::TEXT_IS_EQUAL_TO, 'Test field1 is equal to 123', true], [user_profile::TEXT_IS_NOT_EQUAL_TO, 'Test field1 isn\'t equal to 123', true], - [user_profile::TEXT_STARTS_WITH, 'Test field1 starts with 123', false], - [user_profile::TEXT_ENDS_WITH, 'Test field1 ends with 123', false], + [user_profile::TEXT_STARTS_WITH, 'Test field1 starts with 123', true], + [user_profile::TEXT_ENDS_WITH, 'Test field1 ends with 123', true], [user_profile::TEXT_IS_EMPTY, 'Test field1 is empty', true], - [user_profile::TEXT_IS_NOT_EMPTY, 'Test field1 is not empty', false], + [user_profile::TEXT_IS_NOT_EMPTY, 'Test field1 is not empty', true], ]; }