function members_extended_search($options = array()) { $db_prefix = elgg_get_config('dbprefix'); $query = sanitise_string($options['query']); $options['joins'] = array("JOIN {$db_prefix}users_entity ue ON e.guid = ue.guid", "JOIN {$db_prefix}metadata md on e.guid = md.entity_guid", "JOIN {$db_prefix}metastrings msv ON n_table.value_id = msv.id"); $r_where = ""; $group_guid = $options['group_guid']; if ($group_guid) { $group = get_entity($group_guid); if (elgg_instanceof($group, 'group')) { elgg_set_page_owner_guid($group_guid); $options['joins'][] = "JOIN {$db_prefix}entity_relationships r ON e.guid = r.guid_one"; $r_where = "AND (r.relationship = 'member' AND r.guid_two = '{$group_guid}')"; } } // username and display name $fields = array('username', 'name'); $where = search_get_where_sql('ue', $fields, $options, FALSE); // get the where clauses for the md names // can't use egef_metadata() because the n_table join comes too late. $clauses = _elgg_entities_get_metastrings_options('metadata', array('metadata_names' => $options['metadata_names'])); $options['joins'] = array_merge($clauses['joins'], $options['joins']); // no fulltext index, can't disable fulltext search in this function. // $md_where .= " AND " . search_get_where_sql('msv', array('string'), $options, FALSE); $md_where = "(({$clauses['wheres'][0]}) AND msv.string LIKE '%{$query}%')"; $options['wheres'] = array("(({$where}) OR ({$md_where}) {$r_where})"); // override subtype -- All users should be returned regardless of subtype. $options['subtype'] = ELGG_ENTITIES_ANY_VALUE; $options['count'] = true; $count = elgg_get_entities($options); // no need to continue if nothing here. if (!$count) { return array('entities' => array(), 'count' => $count); } $options['count'] = FALSE; $options['order_by'] = search_get_order_by_sql('e', 'ue', $options['sort'], $options['order']); $entities = elgg_get_entities($options); return array('entities' => $entities, 'count' => $count); }
/** * Get users that match the search parameters. * * Searches on username, display name, and profile fields * * @param string $hook Hook name * @param string $type Hook type * @param array $value Empty array * @param array $params Search parameters * @return array */ function search_users_hook($hook, $type, $value, $params) { $params['joins'] = (array) elgg_extract('joins', $params, array()); $params['wheres'] = (array) elgg_extract('wheres', $params, array()); $db_prefix = elgg_get_config('dbprefix'); $query = sanitise_string($params['query']); $join = "JOIN {$db_prefix}users_entity ue ON e.guid = ue.guid"; array_unshift($params['joins'], $join); // username and display name $fields = array('username', 'name'); $where = search_get_where_sql('ue', $fields, $params, FALSE); // profile fields $profile_fields = array_keys(elgg_get_config('profile_fields')); if (!empty($profile_fields)) { $params['joins'][] = "JOIN {$db_prefix}metadata md on e.guid = md.entity_guid"; $params['joins'][] = "JOIN {$db_prefix}metastrings msv ON n_table.value_id = msv.id"; // get the where clauses for the md names // can't use egef_metadata() because the n_table join comes too late. $clauses = _elgg_entities_get_metastrings_options('metadata', array('metadata_names' => $profile_fields, 'metadata_values' => null, 'metadata_name_value_pairs' => null, 'metadata_name_value_pairs_operator' => null, 'metadata_case_sensitive' => null, 'order_by_metadata' => null, 'metadata_owner_guids' => null)); $params['joins'] = array_merge($clauses['joins'], $params['joins']); // no fulltext index, can't disable fulltext search in this function. // $md_where .= " AND " . search_get_where_sql('msv', array('string'), $params, FALSE); $md_where = "(({$clauses['wheres'][0]}) AND msv.string LIKE '%{$query}%')"; $params['wheres'][] = "(({$where}) OR ({$md_where}))"; } else { $params['wheres'][] = "{$where}"; } // override subtype -- All users should be returned regardless of subtype. $params['subtype'] = ELGG_ENTITIES_ANY_VALUE; $params['count'] = true; $count = elgg_get_entities($params); // no need to continue if nothing here. if (!$count) { return array('entities' => array(), 'count' => $count); } $params['count'] = FALSE; if (isset($params['sort']) || !isset($params['order_by'])) { $params['order_by'] = search_get_order_by_sql('e', 'ue', $params['sort'], $params['order']); } $entities = elgg_get_entities($params); // add the volatile data for why these entities have been returned. foreach ($entities as $entity) { $title = search_get_highlighted_relevant_substrings($entity->name, $query); // include the username if it matches but the display name doesn't. if (false !== strpos($entity->username, $query)) { $username = search_get_highlighted_relevant_substrings($entity->username, $query); $title .= " ({$username})"; } $entity->setVolatileData('search_matched_title', $title); if (!empty($profile_fields)) { $matched = ''; foreach ($profile_fields as $md_name) { $metadata = $entity->{$md_name}; if (is_array($metadata)) { foreach ($metadata as $text) { if (stristr($text, $query)) { $matched .= elgg_echo("profile:{$md_name}") . ': ' . search_get_highlighted_relevant_substrings($text, $query); } } } else { if (stristr($metadata, $query)) { $matched .= elgg_echo("profile:{$md_name}") . ': ' . search_get_highlighted_relevant_substrings($metadata, $query); } } } $entity->setVolatileData('search_matched_description', $matched); } } return array('entities' => $entities, 'count' => $count); }
/** * Returns entities based upon metadata. Also accepts all * options available to elgg_get_entities(). Supports * the singular option shortcut. * * @note Using metadata_names and metadata_values results in a * "names IN (...) AND values IN (...)" clause. This is subtly * differently than default multiple metadata_name_value_pairs, which use * "(name = value) AND (name = value)" clauses. * * When in doubt, use name_value_pairs. * * To ask for entities that do not have a metadata value, use a custom * where clause like this: * * $options['wheres'][] = "NOT EXISTS ( * SELECT 1 FROM {$dbprefix}metadata md * WHERE md.entity_guid = e.guid * AND md.name_id = $name_metastring_id * AND md.value_id = $value_metastring_id)"; * * Note the metadata name and value has been denormalized in the above example. * * @see elgg_get_entities * * @param array $options Array in format: * * metadata_names => null|ARR metadata names * * metadata_values => null|ARR metadata values * * metadata_name_value_pairs => null|ARR ( * name => 'name', * value => 'value', * 'operand' => '=', * 'case_sensitive' => true * ) * Currently if multiple values are sent via * an array (value => array('value1', 'value2') * the pair's operand will be forced to "IN". * If passing "IN" as the operand and a string as the value, * the value must be a properly quoted and escaped string. * * metadata_name_value_pairs_operator => null|STR The operator to use for combining * (name = value) OPERATOR (name = value); default AND * * metadata_case_sensitive => BOOL Overall Case sensitive * * order_by_metadata => null|ARR array( * 'name' => 'metadata_text1', * 'direction' => ASC|DESC, * 'as' => text|integer * ) * Also supports array('name' => 'metadata_text1') * * metadata_owner_guids => null|ARR guids for metadata owners * * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors. * @since 1.7.0 */ function elgg_get_entities_from_metadata(array $options = array()) { $defaults = array('metadata_names' => ELGG_ENTITIES_ANY_VALUE, 'metadata_values' => ELGG_ENTITIES_ANY_VALUE, 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, 'metadata_name_value_pairs_operator' => 'AND', 'metadata_case_sensitive' => true, 'order_by_metadata' => array(), 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE); $options = array_merge($defaults, $options); $singulars = array('metadata_name', 'metadata_value', 'metadata_name_value_pair', 'metadata_owner_guid'); $options = _elgg_normalize_plural_options_array($options, $singulars); if (!($options = _elgg_entities_get_metastrings_options('metadata', $options))) { return false; } return elgg_get_entities($options); }
/** * Returns entities based upon annotations. Also accepts all options available * to elgg_get_entities() and elgg_get_entities_from_metadata(). * * Entity creation time is selected as maxtime. To sort based upon * this, pass 'order_by' => 'maxtime asc' || 'maxtime desc' * * @see elgg_get_entities * @see elgg_get_entities_from_metadata * * @param array $options Array in format: * * annotation_names => null|ARR annotations names * * annotation_values => null|ARR annotations values * * annotation_name_value_pairs => null|ARR (name = 'name', value => 'value', * 'operator' => '=', 'case_sensitive' => true) entries. * Currently if multiple values are sent via an array (value => array('value1', 'value2') * the pair's operator will be forced to "IN". * * annotation_name_value_pairs_operator => null|STR The operator to use for combining * (name = value) OPERATOR (name = value); default AND * * annotation_case_sensitive => BOOL Overall Case sensitive * * order_by_annotation => null|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC, * 'as' => text|integer), * * Also supports array('name' => 'annotation_text1') * * annotation_owner_guids => null|ARR guids for annotaiton owners * * @return mixed If count, int. If not count, array. false on errors. * @since 1.7.0 */ function elgg_get_entities_from_annotations(array $options = array()) { $defaults = array('annotation_names' => ELGG_ENTITIES_ANY_VALUE, 'annotation_values' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs_operator' => 'AND', 'annotation_case_sensitive' => true, 'order_by_annotation' => array(), 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE, 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE, 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE, 'order_by' => 'maxtime DESC', 'group_by' => 'a.entity_guid'); $options = array_merge($defaults, $options); $singulars = array('annotation_name', 'annotation_value', 'annotation_name_value_pair', 'annotation_owner_guid'); $options = _elgg_normalize_plural_options_array($options, $singulars); $options = _elgg_entities_get_metastrings_options('annotation', $options); if (!$options) { return false; } // special sorting for annotations //@todo overrides other sorting $options['selects'][] = "MAX(n_table.time_created) AS maxtime"; $options['group_by'] = 'n_table.entity_guid'; $time_wheres = _elgg_get_entity_time_where_sql('a', $options['annotation_created_time_upper'], $options['annotation_created_time_lower']); if ($time_wheres) { $options['wheres'] = array_merge($options['wheres'], $time_wheres); } return elgg_get_entities_from_metadata($options); }
/** * Returns entities based upon annotations. Also accepts all options available * to elgg_get_entities() and elgg_get_entities_from_metadata(). * * @see elgg_get_entities * @see elgg_get_entities_from_metadata * * @param array $options Array in format: * * annotation_names => null|ARR annotations names * * annotation_values => null|ARR annotations values * * annotation_name_value_pairs => null|ARR (name = 'name', value => 'value', * 'operator' => '=', 'case_sensitive' => true) entries. * Currently if multiple values are sent via an array (value => array('value1', 'value2') * the pair's operator will be forced to "IN". * * annotation_name_value_pairs_operator => null|STR The operator to use for combining * (name = value) OPERATOR (name = value); default AND * * annotation_case_sensitive => BOOL Overall Case sensitive * * order_by_annotation => null|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC, * 'as' => text|integer), * * Also supports array('name' => 'annotation_text1') * * annotation_owner_guids => null|ARR guids for annotaiton owners * * @return mixed If count, int. If not count, array. false on errors. */ function getEntities(array $options = array()) { $defaults = array('annotation_names' => ELGG_ENTITIES_ANY_VALUE, 'annotation_values' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs_operator' => 'AND', 'annotation_case_sensitive' => true, 'order_by_annotation' => array(), 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE, 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE, 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE); $options = array_merge($defaults, $options); $singulars = array('annotation_name', 'annotation_value', 'annotation_name_value_pair', 'annotation_owner_guid'); $options = _elgg_normalize_plural_options_array($options, $singulars); $options = _elgg_entities_get_metastrings_options('annotation', $options); if (!$options) { return false; } // because of performance issues support for ordering by maxtime has been dropped // @see https://github.com/Elgg/Elgg/issues/6638 if (isset($options['order_by']) && preg_match('~\\bmaxtime\\b~i', $options['order_by'])) { // check if the user provided maxtime $deprecated = true; if (isset($options['selects'])) { $selects = $options['selects']; if (!is_array($selects)) { $selects = array($selects); } foreach ($selects as $select) { if (preg_match('~\\bmaxtime\\b~i', $options['order_by'])) { $deprecated = false; break; } } } // the user didn't provide maxtime if ($deprecated) { // special sorting for annotations elgg_deprecated_notice(__FUNCTION__ . ": no longer orders by annotations by default. If you order" . " by maxtime, you must provide that column via \$options['selects']. See" . " https://github.com/Elgg/Elgg/issues/6638#issuecomment-41562034", "1.10"); $options['selects'][] = "MAX(n_table.time_created) AS maxtime"; $options['group_by'] = 'n_table.entity_guid'; } } $time_wheres = _elgg_get_entity_time_where_sql('a', $options['annotation_created_time_upper'], $options['annotation_created_time_lower']); if ($time_wheres) { $options['wheres'] = array_merge($options['wheres'], $time_wheres); } return elgg_get_entities_from_metadata($options); }
/** * {@inheritdoc} */ public static function addSearchQuery(array $options = [], $query = '', array $search_options = []) { if (!$query) { return $options; } $query = sanitize_string(stripslashes($query)); $dbprefix = elgg_get_config('dbprefix'); $options['joins']['objects_entity'] = "\n\t\t\tJOIN {$dbprefix}objects_entity objects_entity\n\t\t\t\tON objects_entity.guid = e.guid\n\t\t\t"; $advanced = elgg_extract('search_tags', $search_options, false); $attribute_names = ['title', 'description']; if (isset($search_options['fields'])) { $search_fields = elgg_extract('fields', $search_options); $attribute_fields = []; $metadata_fields = []; foreach ($search_fields as $search_field) { if (in_array($search_field, $attribute_names)) { $attribute_fields[] = $search_field; } else { $metadata_fields[] = $search_field; $advanced = true; } } } else { $attribute_fields = $attribute_names; $metadata_fields = array_keys((array) elgg_get_registered_tag_metadata_names()); $metadata_fields = array_diff($metadata_fields, $attribute_fields); $advanced = elgg_extract('advanced', $search_options, $advanced); } if (empty($attribute_fields)) { $attribute_fields = ['name']; } $where = self::getFieldSearchWhereClause('objects_entity', $attribute_fields, ['query' => $query], false); if ($advanced && !empty($metadata_fields)) { $options['joins']['metadata_fields_md'] = "\n\t\t\t\tJOIN {$dbprefix}metadata metadata_fields_md\n\t\t\t\t\tON e.guid = metadata_fields_md.entity_guid\n\t\t\t\t"; $options['joins']['metadata_fields_msv'] = "\n\t\t\t\tJOIN {$dbprefix}metastrings metadata_fields_msv\n\t\t\t\t\tON n_table.value_id = metadata_fields_msv.id\n\t\t\t\t"; $clauses = _elgg_entities_get_metastrings_options('metadata', array('metadata_names' => $metadata_fields, 'metadata_values' => null, 'metadata_name_value_pairs' => null, 'metadata_name_value_pairs_operator' => null, 'metadata_case_sensitive' => null, 'order_by_metadata' => null, 'metadata_owner_guids' => null)); $options['joins'] = array_merge($clauses['joins'], $options['joins']); $metadata_fields_md_where = "(({$clauses['wheres'][0]}) AND metadata_fields_msv.string='{$query}')"; $options['wheres'][] = "(({$where}) OR ({$metadata_fields_md_where}))"; } else { $options['wheres'][] = "{$where}"; } return $options; }
/** * Returns entities based upon annotations. Also accepts all options available * to elgg_get_entities() and elgg_get_entities_from_metadata(). * * @see elgg_get_entities * @see elgg_get_entities_from_metadata * * @param array $options Array in format: * * annotation_names => null|ARR annotations names * * annotation_values => null|ARR annotations values * * annotation_name_value_pairs => null|ARR (name = 'name', value => 'value', * 'operator' => '=', 'case_sensitive' => true) entries. * Currently if multiple values are sent via an array (value => array('value1', 'value2') * the pair's operator will be forced to "IN". * * annotation_name_value_pairs_operator => null|STR The operator to use for combining * (name = value) OPERATOR (name = value); default AND * * annotation_case_sensitive => BOOL Overall Case sensitive * * order_by_annotation => null|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC, * 'as' => text|integer), * * Also supports array('name' => 'annotation_text1') * * annotation_owner_guids => null|ARR guids for annotaiton owners * * @return mixed If count, int. If not count, array. false on errors. */ function getEntities(array $options = array()) { $defaults = array('annotation_names' => ELGG_ENTITIES_ANY_VALUE, 'annotation_values' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, 'annotation_name_value_pairs_operator' => 'AND', 'annotation_case_sensitive' => true, 'order_by_annotation' => array(), 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE, 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE, 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE); $options = array_merge($defaults, $options); $singulars = array('annotation_name', 'annotation_value', 'annotation_name_value_pair', 'annotation_owner_guid'); $options = _elgg_normalize_plural_options_array($options, $singulars); $options = _elgg_entities_get_metastrings_options('annotation', $options); if (!$options) { return false; } $time_wheres = _elgg_get_entity_time_where_sql('n_table', $options['annotation_created_time_upper'], $options['annotation_created_time_lower']); if ($time_wheres) { $options['wheres'][] = $time_wheres; } return elgg_get_entities_from_metadata($options); }
/** * Adds search query options to the ege* options array * * @param array $options ege* options * @param string $query Query * @return array */ function user_sort_add_search_query_options(array $options = array(), $query = '') { if (!elgg_is_active_plugin('search') || !$query) { return $options; } $query = sanitize_string($query); $advanced = elgg_extract('advanced_search', $options, false); $dbprefix = elgg_get_config('dbprefix'); $options['joins']['users_entity'] = "JOIN {$dbprefix}users_entity users_entity ON users_entity.guid = e.guid"; $fields = array('name'); if (elgg_get_plugin_setting('username', 'user_sort', true)) { $fields[] = 'username'; } $where = search_get_where_sql('users_entity', $fields, ['query' => $query], false); $profile_fields = array_keys((array) elgg_get_config('profile_fields')); $profile_fields = array_diff($profile_fields, $fields); if ($advanced && !empty($profile_fields)) { $options['joins']['profile_fields_md'] = "JOIN {$dbprefix}metadata profile_fields_md on e.guid = profile_fields_md.entity_guid"; $options['joins']['profile_fields_msv'] = "JOIN {$dbprefix}metastrings profile_fields_msv ON n_table.value_id = profile_fields_msv.id"; $clauses = _elgg_entities_get_metastrings_options('metadata', array('metadata_names' => $profile_fields, 'metadata_values' => null, 'metadata_name_value_pairs' => null, 'metadata_name_value_pairs_operator' => null, 'metadata_case_sensitive' => null, 'order_by_metadata' => null, 'metadata_owner_guids' => null)); $options['joins'] = array_merge($clauses['joins'], $options['joins']); $profile_fields_md_where = "(({$clauses['wheres'][0]}) AND profile_fields_msv.string LIKE '%{$query}%')"; $options['wheres'][] = "(({$where}) OR ({$profile_fields_md_where}))"; } else { $options['wheres'][] = "{$where}"; } return $options; }