From 8672a6157ffba126fab278b85b20ca3b0b7db0b3 Mon Sep 17 00:00:00 2001 From: Peter Velosy Date: Sat, 27 Jul 2024 01:50:00 +0200 Subject: [PATCH] Add internal field "entryteammemberprofilefield" for filtering on a profile field of a user in a "teammemberselect" field. --- .gitignore | 1 + classes/datalynx.php | 3 +- field/datalynxfield_no_content_can_join.php | 25 ++ .../classes/privacy/provider.php | 41 ++++ .../field_class.php | 221 ++++++++++++++++++ ...alynxfield_entryteammemberprofilefield.php | 28 +++ .../entryteammemberprofilefield/pix/icon.gif | Bin 0 -> 92 bytes .../entryteammemberprofilefield/renderer.php | 37 +++ field/entryteammemberprofilefield/version.php | 28 +++ filter/filter_class.php | 14 +- 10 files changed, 393 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 field/datalynxfield_no_content_can_join.php create mode 100644 field/entryteammemberprofilefield/classes/privacy/provider.php create mode 100644 field/entryteammemberprofilefield/field_class.php create mode 100644 field/entryteammemberprofilefield/lang/en/datalynxfield_entryteammemberprofilefield.php create mode 100644 field/entryteammemberprofilefield/pix/icon.gif create mode 100644 field/entryteammemberprofilefield/renderer.php create mode 100644 field/entryteammemberprofilefield/version.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e43b0f98 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/classes/datalynx.php b/classes/datalynx.php index f0889e23..98c71f3d 100644 --- a/classes/datalynx.php +++ b/classes/datalynx.php @@ -849,7 +849,8 @@ public function get_internal_fields() { if (!$fieldclass::is_internal()) { continue; } - $internalfields = $fieldclass::get_field_objects($this->data->id); + // By this time, $this->fields should be filled up. + $internalfields = $fieldclass::get_field_objects($this->data->id, $this->fields); foreach ($internalfields as $fid => $field) { $this->internalfields[$fid] = $this->get_field($field); } diff --git a/field/datalynxfield_no_content_can_join.php b/field/datalynxfield_no_content_can_join.php new file mode 100644 index 00000000..b8ef2f05 --- /dev/null +++ b/field/datalynxfield_no_content_can_join.php @@ -0,0 +1,25 @@ +. + + +/** + * Base class for Datalynx field types that require no content. Example: User profile fields. + */ +abstract class datalynxfield_no_content_can_join extends datalynxfield_no_content { + +} + +?> \ No newline at end of file diff --git a/field/entryteammemberprofilefield/classes/privacy/provider.php b/field/entryteammemberprofilefield/classes/privacy/provider.php new file mode 100644 index 00000000..08e956cb --- /dev/null +++ b/field/entryteammemberprofilefield/classes/privacy/provider.php @@ -0,0 +1,41 @@ +. + +/** + * Privacy provider implementation for datalynxfield_checkbox. + * + * @package datalynxfield + * @subpackage datalynxfield_entryteammemberprofilefield + * @copyright 2018 Michael Pollak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace datalynxfield_entryteammemberprofilefield\privacy; + +class provider implements + // This plugin does not store any personal user data. + \core_privacy\local\metadata\null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/field/entryteammemberprofilefield/field_class.php b/field/entryteammemberprofilefield/field_class.php new file mode 100644 index 00000000..e70da235 --- /dev/null +++ b/field/entryteammemberprofilefield/field_class.php @@ -0,0 +1,221 @@ +. + +/** + * + * @package datalynxfield + * @subpackage entryteammemberprofilefield + * @copyright 2013 onwards edulabs.org and associated programmers + * @copyright based on the work by 2012 Itamar Tzadok + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/mod/datalynx/field/field_class.php'); +require_once($CFG->dirroot . '/mod/datalynx/field/datalynxfield_no_content_can_join.php'); + +class datalynxfield_entryteammemberprofilefield extends datalynxfield_no_content_can_join { + + public $type = 'entryteammemberprofilefield'; + + const SQL_NEVERTRUE = "1 = 0"; + + const OPERATOR_MY_PROFILE_FIELD = 'MY_PROFILE_FIELD'; + const OPERATOR_LITERAL_VALUE = 'LITERAL_VALUE'; + + public function supports_group_by() { + return false; + } + + /** + */ + public static function is_internal() { + return true; + } + + /** + */ + public static function get_field_objects($dataid, $fields = array()) { + $fieldobjects = array(); + + $team_member_select_fields = array_filter($fields, function($field) { + return $field instanceof datalynxfield_teammemberselect; + }); + + $user_profile_fields = array('institution', 'department'); + + foreach ($team_member_select_fields as $field) { + $field_name = $field->field->name; + foreach ($user_profile_fields as $profile_field) { + $field_id = 'entryteammemberprofilefield_' . $field->field->id . "_$profile_field"; + $fieldobjects[$field_id] = (object) array('id' => $field_id, + 'dataid' => $dataid, 'type' => 'entryteammemberprofilefield', + 'name' => $field_name . ' -> ' . get_string($profile_field), 'description' => '', + 'visible' => 2, 'internalname' => $field_id); + } + } + + return $fieldobjects; + } + + /** + */ + protected function get_sql_compare_text($column = 'content') { + global $DB; + // The sort sql here returns the field's sql name. + return $DB->sql_compare_text($this->get_sort_sql()); + } + + public function get_search_from_sql() { + $field_id_components = $this->get_field_id_components(); + $queried_field_id = $field_id_components["queried_field_id"]; + + if (is_numeric($queried_field_id) && $queried_field_id > 0) { + return " LEFT JOIN {datalynx_contents} c$queried_field_id ON c$queried_field_id.entryid = e.id AND c$queried_field_id.fieldid = $queried_field_id "; + } else { + return ""; + } + } + + private function get_field_id_components() { + $components = explode("_", $this->field->id); + return array( + 'queried_field_id' => $components[1], + 'profile_field_name' => $components[2] + ); + } + + /** + */ + public function get_sort_sql() { + return ""; + } + + /** + * {@inheritDoc} + * @see datalynxfield_base::get_search_sql() + */ + public function get_search_sql(array $search): array { + global $DB; + global $USER; + + list($not, $operator, $value) = $search; + + $field_id_components = $this->get_field_id_components(); + $queried_field_id = $field_id_components["queried_field_id"]; + $profile_field_name = $field_id_components["profile_field_name"]; + + $field_id = $this->field->id; + $param_prefix = "df_{$field_id}"; + + $users_with_profile_field_value = $this->get_users_with_profile_field_value($profile_field_name, $operator, $value, $not); + + if (empty($users_with_profile_field_value)) { + $sql = self::SQL_NEVERTRUE; + $params = array(); + $usecontent = false; + } else { + $user_ids = array_map(function($user) {return $user->id;}, $users_with_profile_field_value); + $user_ids_json = array_map(function($id) {return $this->wrap_as_json_string_array($id);}, $user_ids); + + [$insql, $inparams] = $DB->get_in_or_equal($user_ids_json, $type = SQL_PARAMS_NAMED, $param_prefix); + + $sql = "c{$queried_field_id}.content $insql"; + $params = $inparams; + $usecontent = true; + } + + return array($sql, $params, $usecontent); + } + + private function get_users_with_profile_field_value($profile_field_name, $operator, $value, $not) { + global $DB; + global $USER; + + $sql = $not ? + "SELECT u.id + FROM {user} u + WHERE u.$profile_field_name != ?" + : "SELECT u.id + FROM {user} u + WHERE u.$profile_field_name = ?"; + + $search_value = ($operator == self::OPERATOR_MY_PROFILE_FIELD) ? $USER->$profile_field_name : $value; + + return $DB->get_records_sql($sql, array($search_value)); + } + + private function wrap_as_json_string_array($value) { + return "[\"$value\"]"; + } + + public function parse_search($formdata, $i) { + global $USER; + $field_id = $this->field->id; + $internalname = $this->field->internalname; + $operator = !empty($formdata->{"searchoperator{$i}"}) ? $formdata->{"searchoperator{$i}"} : ''; + $fieldvalue = !empty($formdata->{"f_{$i}_$field_id"}) ? $formdata->{"f_{$i}_$field_id"} : false; + if ($operator == self::OPERATOR_MY_PROFILE_FIELD) { + return "-"; // FIXME: Find a way to save the filter without returning any value here. + } else { + if ($operator == self::OPERATOR_LITERAL_VALUE) { + return $fieldvalue; + } else { + return false; + } + } + } + + /** + * returns an array of distinct content of the field + */ + public function get_distinct_content($sortdir = 0) { + global $DB; + + $sortdir = $sortdir ? 'DESC' : 'ASC'; + $contentfull = $this->get_sort_sql(); + $sql = "SELECT DISTINCT $contentfull + FROM {user} u + JOIN {datalynx_entries} e ON u.id = e.userid + WHERE e.dataid = ? AND $contentfull IS NOT NULL + ORDER BY $contentfull $sortdir"; + + $distinctvalues = array(); + if ($options = $DB->get_records_sql($sql, array($this->df->id()))) { + if ($this->field->internalname == 'name') { + $internalname = 'id'; + } else { + $internalname = $this->field->internalname; + } + foreach ($options as $data) { + $value = $data->{$internalname}; + if ($value === '') { + continue; + } + $distinctvalues[] = $value; + } + } + return $distinctvalues; + } + + public function get_supported_search_operators() { + return array( + '' => '<' . get_string('choose') . '>', + self::OPERATOR_LITERAL_VALUE => get_string('literalvalue', 'datalynxfield_entryteammemberprofilefield'), + self::OPERATOR_MY_PROFILE_FIELD => get_string('myprofilefield', 'datalynxfield_entryteammemberprofilefield') + ); + } +} diff --git a/field/entryteammemberprofilefield/lang/en/datalynxfield_entryteammemberprofilefield.php b/field/entryteammemberprofilefield/lang/en/datalynxfield_entryteammemberprofilefield.php new file mode 100644 index 00000000..365ec563 --- /dev/null +++ b/field/entryteammemberprofilefield/lang/en/datalynxfield_entryteammemberprofilefield.php @@ -0,0 +1,28 @@ +. + +/** + * + * @package datalynxfield + * @subpackage entryteammemberprofilefield + * @copyright 2013 onwards edulabs.org and associated programmers + * @copyright based on the work by 2011 Itamar Tzadok + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +$string['pluginname'] = 'Entryteammemberprofilefield'; +$string['myprofilefield'] = 'equal to the value in my profile'; +$string['literalvalue'] = 'literal value:'; +$string['privacy:metadata'] = 'The field entryteammemberprofilefield does not store personal data.'; diff --git a/field/entryteammemberprofilefield/pix/icon.gif b/field/entryteammemberprofilefield/pix/icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..9452b38bd0a6cf1fc9da756e908f7bf1a2c08da0 GIT binary patch literal 92 zcmZ?wbhEHb6krfw_{hv~=FAyJMn(n(hX4QnEB<6*WoKY!&;fFRvH}bYOuBRWSDt>$ wpDeWSRyXsFJ=JeH<(6|UtH{&jnDJJ7k}lW&Pd&RV4)iHc. + +/** + * + * @package datalynxfield + * @subpackage entryauthor + * @copyright 2013 onwards edulabs.org and associated programmers + * @copyright based on the work by 2011 Itamar Tzadok + * @copyright 2013 onwards David Bogner, Michael Pollak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use core_user\fields; + +defined('MOODLE_INTERNAL') || die(); + +require_once("$CFG->dirroot/mod/datalynx/field/renderer.php"); + +/** + */ +class datalynxfield_entryteammemberprofilefield_renderer extends datalynxfield_renderer { + +} diff --git a/field/entryteammemberprofilefield/version.php b/field/entryteammemberprofilefield/version.php new file mode 100644 index 00000000..bd09d490 --- /dev/null +++ b/field/entryteammemberprofilefield/version.php @@ -0,0 +1,28 @@ +. + +/** + * + * @package datalynxfield + * @subpackage entryteammemberprofilefield + * @copyright 2015 David Bogner {@link http:// Www.edulabs.org}. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +$plugin->component = 'datalynxfield_entryteammemberprofilefield'; +$plugin->version = 2015092200; +$plugin->requires = 2014051200; diff --git a/filter/filter_class.php b/filter/filter_class.php index 198f00c5..568c1d2b 100644 --- a/filter/filter_class.php +++ b/filter/filter_class.php @@ -198,8 +198,11 @@ public function get_search_sql($fields) { $searchparams = array_merge($searchparams, $fieldparams); // Add searchfrom (JOIN) only for search in datalynx content or external. - // Tables. - if (!$internalfield && $fromcontent) { + // tables or fields inherited from datalynxfield_no_content_can_join. + + $field_should_add_join = !$internalfield || $field instanceof datalynxfield_no_content_can_join; + + if ($field_should_add_join && $fromcontent) { $searchfrom[$fieldid] = $fieldid; } } @@ -221,8 +224,11 @@ public function get_search_sql($fields) { $searchparams = array_merge($searchparams, $fieldparams); // Add searchfrom (JOIN) only for search in datalynx content or external. - // Tables. - if (!$internalfield && $fromcontent) { + // tables or fields inherited from datalynxfield_no_content_can_join. + + $field_should_add_join = !$internalfield || $field instanceof datalynxfield_no_content_can_join; + + if ($field_should_add_join && $fromcontent) { $searchfrom[$fieldid] = $fieldid; } }