Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@deepagupta
Created April 11, 2012 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deepagupta/2362199 to your computer and use it in GitHub Desktop.
Save deepagupta/2362199 to your computer and use it in GitHub Desktop.
search for tags when a partial string is provided
<?php
/**
* @auth: d.gupta
* @date: Apr/11/12
* @desc: This file (start.php) along a manifest file constitute a plugin namely "search_extension" that extends the "search"
The core plugin "search" displays tag results only if the inputted string matches the tags exactly and completely
[concerned code: search_tag_hook(..) in /mod/search/search_hooks.php]
However, the following code overrides it by correctly displaying the tag-search-results even when the searched string is a substring of the tag
ANY IMPROVEMENTS/FEEDBACK IS HIGHLY APPRECIATED.
Why this isn't posted as a plugin yet:
From the comments, it seems that there is work and improvements already on its way by the core developers. I am hopeful
to have this worked out in the future versions of the Elgg thereby not requiring this as a plugin at all. Or else, if
not, I look forward to have some feedback before going down that path
*/
elgg_register_event_handler('init','system','search_extension_init');
function search_extension_init(){
elgg_unregister_plugin_hook_handler('search','tags','search_tags_hook');
elgg_register_plugin_hook_handler('search', 'tags', 'search_extension_tags_hook');
}
/**
* Return default results for searches on tags.
*
* @param unknown_type $hook
* @param unknown_type $type
* @param unknown_type $value
* @param unknown_type $params
* @return unknown_type
*/
function search_extension_tags_hook($hook, $type, $value, $params) {
$db_prefix = elgg_get_config('dbprefix');
static $iteration = 0;
$iteration++;
$valid_tag_names = elgg_get_registered_tag_metadata_names();
// @todo will need to split this up to support searching multiple tags at once.
$query = sanitise_string($params['query']);
// if passed a tag metadata name, only search on that tag name.
// tag_name isn't included in the params because it's specific to
// tag searches.
if ($tag_names = get_input('tag_names')) {
if (is_array($tag_names)) {
$search_tag_names = $tag_names;
} else {
$search_tag_names = array($tag_names);
}
// check these are valid to avoid arbitrary metadata searches.
foreach ($search_tag_names as $i => $tag_name) {
if (!in_array($tag_name, $valid_tag_names)) {
unset($search_tag_names[$i]);
}
}
} else {
$search_tag_names = $valid_tag_names;
}
if (!$search_tag_names) {
return array('entities' => array(), 'count' => $count);
}
// don't use elgg_get_entities_from_metadata() here because of
// performance issues. since we don't care what matches at this point
// use an IN clause to grab everything that matches at once and sort
// out the matches later.
$params['joins'][] = "JOIN {$db_prefix}metadata md on e.guid = md.entity_guid";
$params['joins'][] = "JOIN {$db_prefix}metastrings msn on md.name_id = msn.id";
$params['joins'][] = "JOIN {$db_prefix}metastrings msv on md.value_id = msv.id";
$access = get_access_sql_suffix('md');
$sanitised_tags = array();
foreach ($search_tag_names as $tag) {
$sanitised_tags[] = '"' . sanitise_string($tag) . '"';
}
$tags_in = implode(',', $sanitised_tags);
/** @auth: d.gupta @date: Apr/11/12
* changed query to LIKE %query% so as to match tags with partial string
*/
$params['wheres'][] = "(msn.string IN ($tags_in) AND msv.string LIKE '%$query%' AND $access)";
$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;
$entities = elgg_get_entities($params);
// add the volatile data for why these entities have been returned.
foreach ($entities as $entity) {
$matched_tags_strs = array();
// get tags for each tag name requested to find which ones matched.
foreach ($search_tag_names as $tag_name) {
$tags = $entity->getTags($tag_name);
// @todo make one long tag string and run this through the highlight
// function. This might be confusing as it could chop off
// the tag labels.
/* @auth: d.gupta @date: Apr/11/12 ----------- */
/* @desc: this is done for getting display of tags-search-result right. following code modified from the original for replacing the condtion: "in_array(strtolower($query), array_map('strtolower', $tags))" by our calculated boolean: "$query_is_in_tags" (boolean)"
* how this makes a difference: our calculated condition ($query_is_in_tags) returns true if the searched string is contained/is a substring of the actual tag of the entity
*the former/orginial code displayed & highlighted the searched tag only if the searched string exactly matched the entity's tag whereas
*/
$query_lower = strtolower($query);
$tags_lower = array_map('strtolower',$tags);
$query_is_in_tags = false;
foreach($tags_lower as $tag_element){
if(strpos($tag_element,$query_lower)>=0){
$query_is_in_tags = true;
}
}
if ($query_is_in_tags) {
// ------------------------------------------------------//
if (is_array($tags)) {
$tag_name_str = elgg_echo("tag_names:$tag_name");
$matched_tags_strs[] = "$tag_name_str: " . implode(', ', $tags);
}
}
}
// different entities have different titles
switch($entity->type) {
case 'site':
case 'user':
case 'group':
$title_tmp = $entity->name;
break;
case 'object':
$title_tmp = $entity->title;
break;
}
// Nick told me my idea was dirty, so I'm hard coding the numbers.
$title_tmp = strip_tags($title_tmp);
if (elgg_strlen($title_tmp) > 297) {
$title_str = elgg_substr($title_tmp, 0, 297) . '...';
} else {
$title_str = $title_tmp;
}
$desc_tmp = strip_tags($entity->description);
if (elgg_strlen($desc_tmp) > 297) {
$desc_str = elgg_substr($desc_tmp, 0, 297) . '...';
} else {
$desc_str = $desc_tmp;
}
$tags_str = implode('. ', $matched_tags_strs);
$tags_str = search_get_highlighted_relevant_substrings($tags_str, $params['query']);
$entity->setVolatileData('search_matched_title', $title_str);
$entity->setVolatileData('search_matched_description', $desc_str);
$entity->setVolatileData('search_matched_extra', $tags_str);
}
return array(
'entities' => $entities,
'count' => $count,
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment