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;
142 $FieldId, $CurrentValue, $CurrentDisplayValue,
143 $CloneAfter=FALSE, $FormFieldName=NULL)
146 $GLOBALS[
"AF"]->RequireUIFile(
"jquery-ui.js");
147 $GLOBALS[
"AF"]->RequireUIFile(
"CW-QuickSearch.js");
149 if (is_numeric($FieldId))
153 if ($FormFieldName === NULL)
155 $FormFieldName =
"F_".$Field->DBFieldName();
157 $SafeFieldId = intval($FieldId);
159 elseif ($FieldId ==
"UserSearch")
161 if ($FormFieldName === NULL)
164 "FormFieldName required for User Quick Search elements.");
166 $SafeFieldId = $FieldId;
170 throw new Exception(
"Invalid FieldId");
174 $SafeCurrentValue = defaulthtmlentities($CurrentValue);
175 $SafeCurrentDisplayValue = defaulthtmlentities($CurrentDisplayValue);
178 <div
class=
"cw-quicksearch cw-quicksearch-fieldid-<?= $SafeFieldId ?>" 179 data-fieldid=
"<?= $SafeFieldId ?>">
180 <textarea
class=
"cw-quicksearch-display cw-resourceeditor-metadatafield 181 <?= $FormFieldName; ?> cw-autoresize"><?= $SafeCurrentDisplayValue ?></textarea>
182 <input name=
"<?= $FormFieldName ?>[]" 183 class=
"cw-quicksearch-value" type=
"hidden" value=
"<?= $SafeCurrentValue ?>" />
184 <div style=
"display: none;" class=
'cw-quicksearch-menu'>
185 <div
class=
'cw-quicksearch-message ui-front'></div>
188 <?
PHP if ($CloneAfter) {?>
189 <div
class=
"cw-quicksearch-template cw-quicksearch cw-quicksearch-fieldid-<?= $SafeFieldId; ?>" 190 style=
"display: none;" data-fieldid=
"<?= $SafeFieldId; ?>">
191 <textarea
class=
"cw-quicksearch-display cw-resourceeditor-metadatafield 192 <?= $FormFieldName; ?> cw-autoresize"></textarea>
193 <input name=
"<?= $FormFieldName; ?>[]" 194 class=
"cw-quicksearch-value" type=
"hidden" value=
"<?= $SafeCurrentValue ?>" />
195 <div style=
"display: none;" class=
'cw-quicksearch-menu'>
196 <div
class=
'cw-quicksearch-message ui-front'></div>
216 array $IdExclusions=array(),
217 array $ValueExclusions=array())
219 # the factory used for searching 222 # get the minimum word length for fuzzy query matching 224 $MinLen = intval($MysqlSysVars->Get(
"ft_min_word_len"));
226 # initialize the result variables 227 $SearchResults = array();
228 $ResultsNeeded = $MaxResults;
230 # if the search string is less than the minimum length, do exact query 232 if (strlen($SearchString) < $MinLen)
234 $SearchResults = $UserFactory->FindUserNames(
236 "UserName",
"UserName", 0, # defaults
241 # decrement the max results by how many were found 242 $ResultsNeeded -= count($SearchResults);
245 # if there are still some results to fetch, perform fuzzy matching 246 if ($ResultsNeeded > 0)
248 $FuzzyResults = $UserFactory->GetMatchingUsers(
252 # filter results based on Id and Value exclusions 253 foreach ($FuzzyResults as $UserId => $Result)
255 if (!in_array($UserId, $IdExclusions) &&
256 !in_array($Result[
"UserName"], $ValueExclusions))
258 $SearchResults[$UserId] = $Result[
"UserName"];
263 # slice out just the results we want 264 $TotalResults = count($SearchResults);
265 $SearchResults = array_slice($SearchResults, 0, $MaxResults, TRUE);
267 $NumResults = count($SearchResults);
268 $NumAdditionalResults = $TotalResults - $NumResults;
270 return array($NumResults, $NumAdditionalResults, $SearchResults);
278 private static function PrepareSearchString($SearchString)
280 # remove "--", which causes searches to fail and is often in classifications 281 # Also remove unwanted punctuation 282 $SearchString = str_replace(
283 array(
"--",
",",
".",
":"),
" ", $SearchString);
285 # split the search string into words 286 $Words = preg_split(
'/\s+/', $SearchString, -1, PREG_SPLIT_NO_EMPTY);
288 # the variable that holds the prepared search string 289 $PreparedSearchString =
"";
290 $InQuotedString = FALSE;
292 # iterate over all the words 293 foreach ($Words as $Word)
295 # include quoted strings directly 296 $InQuotedString |= preg_match(
'/^[+-]?"/', $Word);
299 $PreparedSearchString .= $Word.
" ";
300 $InQuotedString &= (substr($Word, -1) !=
'"');
302 # append a * to every word outside a quoted string 303 elseif (strlen($Word)>1)
305 $PreparedSearchString .= $Word.
"* ";
309 # clean up trailing whitespace, ensure quotes are closed 310 $PreparedSearchString = trim($PreparedSearchString);
313 $PreparedSearchString .=
'"';
316 return $PreparedSearchString;
343 private static function SortSearchResults($Results, $SearchString, $MaxResults)
352 "Other" => array() );
354 # escape regex characters 355 $SafeStr = preg_quote( trim( preg_replace(
'/\s+/',
" ",
356 str_replace( array(
"--",
",",
".",
":"),
" ",
357 $SearchString) )),
'/');
359 # iterate over search results, sorting them into bins 360 foreach ($Results as $Key => $Val)
362 # apply the same normalization to our value as we did our search string 363 $TestVal = preg_quote( trim( preg_replace(
'/\s+/',
" ",
364 str_replace( array(
"--",
",",
".",
":"),
" ",
367 if (preg_match(
'/^'.$SafeStr.
'$/i', $TestVal))
371 elseif (preg_match(
'/^'.$SafeStr.
'\\W/i', $TestVal))
375 elseif (preg_match(
'/^'.$SafeStr.
'/i', $TestVal))
379 elseif (preg_match(
'/'.$SafeStr.
'$/i', $TestVal))
383 elseif (preg_match(
'/'.$SafeStr.
'\\W/i', $TestVal))
387 elseif (preg_match(
'/'.$SafeStr.
'/i', $TestVal))
396 $Matches[$ix][$Key] = $Val;
399 # assemble the sorted results 400 $SortedResults = array();
401 foreach (array(
"Exact",
"BegSp",
"Beg",
"End",
"MidSp",
"Mid",
"Other") as $ix)
403 asort( $Matches[$ix] );
404 $SortedResults += $Matches[$ix];
407 # trim down the list to the requested number 408 $SortedResults = array_slice($SortedResults, 0, $MaxResults, TRUE);
410 return $SortedResults;
424 private static function SearchForResources(
428 array $IdExclusions=array() )
430 # construct search groups based on the keyword 432 $SearchParams->AddParameter($SearchString);
434 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
435 "EVENT_FIELD_SEARCH_FILTER",
437 "Search" => $SearchParams,
438 "Field" => $DstField));
439 $SearchParams = $SignalResult[
"Search"];
443 $SearchResults = $SearchEngine->SearchAll($SearchParams);
445 # get the list of referenceable schemas for this field 446 $ReferenceableSchemaIds = $DstField->ReferenceableSchemaIds();
448 # iterate over search results from desired schemas 449 $SearchResultsNew = array();
450 foreach ($SearchResults as $SchemaId => $SchemaResults)
452 if (in_array($SchemaId, $ReferenceableSchemaIds))
454 # filter resources the user cannot see 456 $ViewableIds = $RFactory->FilterNonViewableResources(
457 array_keys($SchemaResults), $GLOBALS[
"G_User"]);
459 # add these results to our list of all search results 460 $SearchResultsNew += array_intersect_key(
461 $SchemaResults, array_flip($ViewableIds));
464 $SearchResults = $SearchResultsNew;
466 # filter out excluded resource IDs if necessary 467 if (count($IdExclusions))
469 $SearchResults = array_diff_key(
470 $SearchResults, array_flip($IdExclusions));
473 # pull out mapped titles for all resources 474 $GLOBALS[
"AF"]->LoadFunction(
"GetResourceFieldValue");
475 $ResourceData = array();
476 foreach ($SearchResults as $ResourceId => $Score)
478 $Resource =
new Resource($ResourceId);
479 $ResourceData[$ResourceId] = GetResourceFieldValue(
481 $Resource->Schema()->GetFieldByMappedName(
"Title") );
484 # determine how many results we had in total 485 $TotalResults = count($ResourceData);
487 # sort resources by title and subset if necessary 488 $ResourceData = self::SortSearchResults(
493 # compute the number of available and additional results 494 $NumSearchResults = count($ResourceData);
495 $NumAdditionalSearchResults = $TotalResults - count($ResourceData);
497 return array($NumSearchResults, $NumAdditionalSearchResults, $ResourceData);
511 private static function SearchForValues(
516 array $ValueExclusions)
520 # get the minimum word length for fuzzy query matching 522 $MinLen = intval($MysqlSysVars->Get(
"ft_min_word_len"));
524 # initialize the result variables 528 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
529 "EVENT_FIELD_SEARCH_FILTER",
531 "Search" => $SearchString,
533 $SearchString = $SignalResult[
"Search"];
535 # if the search string is less than the minimum length, do exact query 537 if (strlen($SearchString) < $MinLen)
539 # search for results and get the total 540 $Results += $Factory->SearchForItemNames(
543 FALSE, TRUE, 0, # defaults
546 $Total += $Factory->GetCountForItemNames(
548 FALSE, TRUE, # defaults,
552 # decrement the max results by how many were returned when doing exact 554 $MaxResults -= count($Results);
557 # if more results should be fetched 560 $PreparedSearchString = self::PrepareSearchString($SearchString);
562 if (strlen($SearchString) >= $MinLen)
564 $Results += $Factory->FindMatchingRecentlyUsedValues(
565 $PreparedSearchString, 5, $IdExclusions, $ValueExclusions);
569 $Results += array(-1 =>
"<hr>");
573 # search for results and get the total 574 $Results += self::SortSearchResults(
575 $Factory->SearchForItemNames(
576 $PreparedSearchString,
578 FALSE, TRUE, 0, # defaults
583 $Total += $Factory->GetCountForItemNames(
584 $PreparedSearchString,
585 FALSE, TRUE, # defaults,
590 # get additional totals 591 $NumSearchResults = count($Results);
592 $NumAdditionalSearchResults = $Total - $NumSearchResults;
594 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 PrintQuickSearchField($FieldId, $CurrentValue, $CurrentDisplayValue, $CloneAfter=FALSE, $FormFieldName=NULL)
Print the blank text field quick search field for the QuickSearch JS object.
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.
const ORDER_FIRST
Handle item first (i.e.
Represents a "resource" in CWIS.
static SearchForUsers($SearchString, $MaxResults=15, array $IdExclusions=array(), array $ValueExclusions=array())
Perform a search for users.
Convenience class for QuickSearch responses, making it easy to share functions common to different ty...
Factory for Resource objects.