3 # FILE: QuickSearchHelper.php 5 # Part of the Collection Workflow Integration System (CWIS) 6 # Copyright 2002-2015 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu/cwis/ 29 array $IdExclusions=array(),
30 array $ValueExclusions=array())
34 switch ($Field->
Type())
37 return self::SearchForUsers(
38 $SearchString, $MaxResults, $IdExclusions, $ValueExclusions);
41 if (count($ValueExclusions))
44 "Cannot exclude resource by value. " 45 .
"Did you want IdExclusions instead?");
48 return self::SearchForResources(
49 $Field, $SearchString, $MaxResults, $IdExclusions);
52 return self::SearchForValues(
53 $Field, $SearchString, $MaxResults, $IdExclusions, $ValueExclusions);
65 if(!is_array($SearchTerms))
67 $SearchTerms = array($SearchTerms);
70 foreach ($SearchTerms as $SearchString)
72 $SearchString = trim($SearchString);
73 $ExplodedSearch = preg_split(
'/\s+/', $SearchString);
78 #Iterate through each term in the search string 79 foreach ($ExplodedSearch as $Term)
81 #Handle quoted terms differently 82 #if the first character is a quote 88 if (substr($Term, -1) ==
'"')
90 #last character is a quote means that we've found the end of the term. 94 #remove all of the quotes if we're matched 95 $Term = str_replace(
'"',
"", $Term);
97 #Add the term to the list of patterns we'll be highlighting in the result 98 # string at the current index (quoted terms will be appended to the index, 99 # unquoted terms are added at a new index). 100 $Patterns[$Index] = (isset($Patterns[$Index]) ?
101 $Patterns[$Index].
" ":
"").$Term;
105 # if we are not in a quoted term, the next term should go at 106 # a new index in the pattern array. 111 # iterate over our terms, escaping them and including bolding 112 # for segments two more ore characters longer 113 $PregPatterns = array();
114 foreach ($Patterns as $Term)
116 if (strlen($Term)>=2)
118 $PregPatterns =
"/".preg_quote($Term,
"/").
"/i";
122 # do the highlighting 123 $LabelForFormatting = preg_replace(
124 $PregPatterns,
"<b>$0</b>", $LabelForFormatting);
128 return $LabelForFormatting;
136 private static function PrepareSearchString($SearchString)
138 # remove "--", which causes searches to fail and is often in classifications 139 # Also remove unwanted punctuation 140 $SearchString = str_replace(
141 array(
"--",
",",
".",
":"),
144 # split the search string into words 145 $Words = preg_split(
'/\s+/', $SearchString, -1, PREG_SPLIT_NO_EMPTY);
147 # the variable that holds the prepared search string 148 $PreparedSearchString =
"";
150 foreach ($Words as $Word)
152 # Don't do one-character "words". 153 if (strlen($Word)==1)
158 # just add the word if it's quoted or has an asterisk already 159 if (preg_match(
'/\"$/', $Word) || preg_match(
'/\*$/', $Word))
161 $PreparedSearchString .= $Word .
" ";
164 # add wildcard operator for stemming 167 $PreparedSearchString .= $Word .
"* ";
171 # remove whitespace padding 172 $PreparedSearchString = trim($PreparedSearchString);
174 return $PreparedSearchString;
201 private static function SortSearchResults($Results, $SearchString, $MaxResults)
210 "Other" => array() );
212 # escape regex characters 213 $SafeStr = preg_quote( trim( preg_replace(
'/\s+/',
" ",
214 str_replace( array(
"--",
",",
".",
":"),
" ",
215 $SearchString) )),
'/');
217 # iterate over search results, sorting them into bins 218 foreach ($Results as $Key => $Val)
220 # apply the same normalization to our value as we did our search string 221 $TestVal = preg_quote( trim( preg_replace(
'/\s+/',
" ",
222 str_replace( array(
"--",
",",
".",
":"),
" ",
225 if (preg_match(
'/^'.$SafeStr.
'$/i', $TestVal))
229 elseif (preg_match(
'/^'.$SafeStr.
'\\W/i', $TestVal))
233 elseif (preg_match(
'/^'.$SafeStr.
'/i', $TestVal))
237 elseif (preg_match(
'/'.$SafeStr.
'$/i', $TestVal))
241 elseif (preg_match(
'/'.$SafeStr.
'\\W/i', $TestVal))
245 elseif (preg_match(
'/'.$SafeStr.
'/i', $TestVal))
254 $Matches[$ix][$Key] = $Val;
257 # assemble the sorted results 258 $SortedResults = array();
259 foreach (array(
"Exact",
"BegSp",
"Beg",
"End",
"MidSp",
"Mid",
"Other") as $ix)
261 asort( $Matches[$ix] );
262 $SortedResults += $Matches[$ix];
265 # trim down the list to the requested number 266 $SortedResults = array_slice($SortedResults, 0, $MaxResults, TRUE);
268 return $SortedResults;
282 private static function SearchForResources(
286 array $IdExclusions=array() )
288 # construct search groups based on the keyword 290 $SearchParams->AddParameter($SearchString);
292 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
293 "EVENT_FIELD_SEARCH_FILTER",
295 "Search" => $SearchParams,
296 "Field" => $DstField));
297 $SearchParams = $SignalResult[
"Search"];
301 $SearchResults = $SearchEngine->Search($SearchParams);
303 # get the list of referenceable schemas for this field 304 $ReferenceableSchemaIds = $DstField->ReferenceableSchemaIds();
306 # iterate over search results from desired schemas 307 $SearchResultsNew = array();
308 foreach ($SearchResults as $SchemaId => $SchemaResults)
310 if (in_array($SchemaId, $ReferenceableSchemaIds))
312 # filter resources the user cannot see 314 $ViewableIds = $RFactory->FilterNonViewableResources(
315 array_keys($SchemaResults), $GLOBALS[
"G_User"]);
317 # add these results to our list of all search results 318 $SearchResultsNew += array_intersect_key(
319 $SchemaResults, array_flip($ViewableIds));
322 $SearchResults = $SearchResultsNew;
324 # filter out excluded resource IDs if necessary 325 if (count($IdExclusions))
327 $SearchResults = array_diff_key(
328 $SearchResults, array_flip($IdExclusions));
331 # pull out mapped titles for all resources 332 $GLOBALS[
"AF"]->LoadFunction(
"GetResourceFieldValue");
333 $ResourceData = array();
334 foreach ($SearchResults as $ResourceId => $Score)
336 $Resource =
new Resource($ResourceId);
337 $ResourceData[$ResourceId] = GetResourceFieldValue(
339 $Resource->Schema()->GetFieldByMappedName(
"Title") );
342 # determine how many results we had in total 343 $TotalResults = count($ResourceData);
345 # sort resources by title and subset if necessary 346 $ResourceData = self::SortSearchResults(
351 # compute the number of available and additional results 352 $NumSearchResults = count($ResourceData);
353 $NumAdditionalSearchResults = $TotalResults - count($ResourceData);
355 return array($NumSearchResults, $NumAdditionalSearchResults, $ResourceData);
367 private static function SearchForUsers(
370 array $IdExclusions=array(),
371 array $ValueExclusions=array())
373 # the factory used for searching 376 # get the minimum word length for fuzzy query matching 378 $MinLen = intval($MysqlSysVars->Get(
"ft_min_word_len"));
380 # initialize the result variables 381 $SearchResults = array();
382 $ResultsNeeded = $MaxResults;
384 # if the search string is less than the minimum length, do exact query 386 if (strlen($SearchString) < $MinLen)
388 $SearchResults = $UserFactory->FindUserNames(
390 "UserName",
"UserName", 0, # defaults
395 # decrement the max results by how many were found 396 $ResultsNeeded -= count($SearchResults);
399 # if there are still some results to fetch, perform fuzzy matching 400 if ($ResultsNeeded > 0)
402 # prepare the search string 403 $PreparedSearchString = self::PrepareSearchString($SearchString);
406 $SearchResults += $UserFactory->FindUserNames(
407 $PreparedSearchString,
408 "UserName",
"UserName", 0, # defaults
414 # slice out just the results we want 415 $TotalResults = count($SearchResults);
416 $SearchResults = array_slice($SearchResults, 0, $MaxResults, TRUE);
418 $NumResults = count($SearchResults);
419 $NumAdditionalResults = $TotalResults - $NumResults;
421 return array($NumResults, $NumAdditionalResults, $SearchResults);
435 private static function SearchForValues(
440 array $ValueExclusions)
444 # get the minimum word length for fuzzy query matching 446 $MinLen = intval($MysqlSysVars->Get(
"ft_min_word_len"));
448 # initialize the result variables 452 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
453 "EVENT_FIELD_SEARCH_FILTER",
455 "Search" => $SearchString,
457 $SearchString = $SignalResult[
"Search"];
459 # if the search string is less than the minimum length, do exact query 461 if (strlen($SearchString) < $MinLen)
463 # search for results and get the total 464 $Results += $Factory->SearchForItemNames(
467 FALSE, TRUE, 0, # defaults
470 $Total += $Factory->GetCountForItemNames(
472 FALSE, TRUE, # defaults,
476 # decrement the max results by how many were returned when doing exact 478 $MaxResults -= count($Results);
481 # if more results should be fetched 484 $PreparedSearchString = self::PrepareSearchString($SearchString);
486 if (strlen($SearchString) >= $MinLen)
488 $Results += $Factory->FindMatchingRecentlyUsedValues(
489 $PreparedSearchString, 5, $IdExclusions, $ValueExclusions);
493 $Results += array(-1 =>
"<hr>");
497 # search for results and get the total 498 $Results += self::SortSearchResults(
499 $Factory->SearchForItemNames(
500 $PreparedSearchString,
502 FALSE, TRUE, 0, # defaults
507 $Total += $Factory->GetCountForItemNames(
508 $PreparedSearchString,
509 FALSE, TRUE, # defaults,
514 # get additional totals 515 $NumSearchResults = count($Results);
516 $NumAdditionalSearchResults = $Total - $NumSearchResults;
518 return array($NumSearchResults, $NumAdditionalSearchResults, $Results);
Set of parameters used to perform a search.
static HighlightSearchString($SearchTerms, $LabelForFormatting)
Highlight all instances of the search string in the result label.
static SearchField(MetadataField $Field, $SearchString, array $IdExclusions=array(), array $ValueExclusions=array())
Search a field for values matching a specified search string.
Class that allows permits easier access to MySQL system variables.
CWIS-specific user factory class.
Represents a "resource" in CWIS.
Convenience class for QuickSearch responses, making it easy to share functions common to different ty...
Factory for Resource objects.