diff --git a/classes/condition_base.php b/classes/condition_base.php index 75df2c2..65ecda9 100644 --- a/classes/condition_base.php +++ b/classes/condition_base.php @@ -55,6 +55,11 @@ abstract class condition_base { */ public const FIELD_DATA_TYPE_DATETIME = 'datetime'; + /** + * Value for autocomplete field types. + */ + public const FIELD_DATA_TYPE_AUTOCOMPLETE = 'autocomplete'; + /** * Value for operator text contains. */ diff --git a/classes/local/tool_dynamic_cohorts/condition/fields_trait.php b/classes/local/tool_dynamic_cohorts/condition/fields_trait.php index 4b9727d..442a7e3 100644 --- a/classes/local/tool_dynamic_cohorts/condition/fields_trait.php +++ b/classes/local/tool_dynamic_cohorts/condition/fields_trait.php @@ -411,4 +411,73 @@ protected function get_date_sql(string $tablealias, string $fieldname): conditio return new condition_sql('', $where, $params); } + + /** + * Get SQL data for multi select type fields. + * + * @param string $tablealias Alias for a table. + * @param string $fieldname Field name. + * @param bool $addspace Does a field type add space? + * @return condition_sql + */ + protected function get_multiselect_sql(string $tablealias, string $fieldname, bool $addspace = true): condition_sql { + global $DB; + + $fieldvalue = $this->get_field_value(); + $operatorvalue = $this->get_operator_value(); + + if ($this->is_broken()) { + return new condition_sql('', '', []); + } + // For some reason user profile field autocomplete adds space when saving field values + // like implode(', ', $data). However multiselect custom field doesn't do it, instead it does + // like implode(',', $data). To make it flexible we add space when we consider (or not) an extra + // space when we build following SQL. + $space = $addspace ? ' ' : ''; + + // User data for multiselect fields is stored like Option 1, Option 2, Option 3. + // So to be accurate in our SQL we have to cover three scenarios: + // 1. Value is in the beginning of the string. + // 2. Value is somewhere in the middle. + // 3. Value is at the end of the string. + // So our SQL should like: + // WHERE data like 'value%' OR data like '% value, %' OR data like '%, value' + // This is a bit hacky, but should give us accurate results. + $startparam = condition_sql::generate_param_alias(); + $middleparam = condition_sql::generate_param_alias(); + $endparam = condition_sql::generate_param_alias(); + + switch ($operatorvalue) { + case self::TEXT_IS_EQUAL_TO: + $value = $DB->sql_like_escape($fieldvalue); + + $where = $DB->sql_like("$tablealias.$fieldname", ":$startparam", false, false); + $params[$startparam] = "$value%"; + + $where .= ' OR ' . $DB->sql_like("$tablealias.$fieldname", ":$middleparam", false, false); + $params[$middleparam] = "%,$space$value,$space%"; + + $where .= ' OR ' . $DB->sql_like("$tablealias.$fieldname", ":$endparam", false, false); + $params[$endparam] = "%,$space$value"; + + break; + case self::TEXT_IS_NOT_EQUAL_TO: + $value = $DB->sql_like_escape($fieldvalue); + + $where = $DB->sql_like("$tablealias.$fieldname", ":$startparam", false, false, true); + $params[$startparam] = "$value%"; + + $where .= ' AND ' . $DB->sql_like("$tablealias.$fieldname", ":$middleparam", false, false, true); + $params[$middleparam] = "%,$space$value,$space%"; + + $where .= ' AND ' . $DB->sql_like("$tablealias.$fieldname", ":$endparam", false, false, true); + $params[$endparam] = "%,$space$value"; + + break; + default: + return new condition_sql('', '', []); + } + + return new condition_sql('', $where, $params); + } } 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 958356f..7508567 100644 --- a/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php +++ b/classes/local/tool_dynamic_cohorts/condition/user_custom_profile.php @@ -53,8 +53,13 @@ public function get_name(): string { * @return array */ protected function get_supported_custom_fields(): array { - return [self::FIELD_DATA_TYPE_TEXT, self::FIELD_DATA_TYPE_MENU, - self::FIELD_DATA_TYPE_CHECKBOX, self::FIELD_DATA_TYPE_DATETIME]; + return [ + self::FIELD_DATA_TYPE_TEXT, + self::FIELD_DATA_TYPE_MENU, + self::FIELD_DATA_TYPE_CHECKBOX, + self::FIELD_DATA_TYPE_DATETIME, + self::FIELD_DATA_TYPE_AUTOCOMPLETE, + ]; } /** @@ -79,6 +84,7 @@ protected function get_fields_info(): array { switch ($field->datatype) { case self::FIELD_DATA_TYPE_MENU: + case self::FIELD_DATA_TYPE_AUTOCOMPLETE: $options = explode("\n", $field->param1); $field->param1 = array_combine($options, $options); break; @@ -124,6 +130,7 @@ public function config_form_add(\MoodleQuickForm $mform): void { $this->add_text_field($mform, $group, $field, $shortname); break; case self::FIELD_DATA_TYPE_MENU: + case self::FIELD_DATA_TYPE_AUTOCOMPLETE: $this->add_menu_field($mform, $group, $field, $shortname); break; case self::FIELD_DATA_TYPE_CHECKBOX: @@ -192,6 +199,9 @@ public function get_sql(): condition_sql { case self::FIELD_DATA_TYPE_DATETIME: $result = $this->get_date_sql($ud, 'data'); break; + case self::FIELD_DATA_TYPE_AUTOCOMPLETE: + $result = $this->get_multiselect_sql($ud, 'data'); + break; } if (!empty($result->get_params())) {