3 # FILE: SavedSearch.php 5 # Part of the Collection Workflow Integration System (CWIS) 6 # Copyright 2011-2015 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu/cwis/ 13 # ---- PUBLIC INTERFACE -------------------------------------------------- 15 # search frequency mnemonics 34 public function __construct($SearchId, $SearchName = NULL, $UserId = NULL,
35 $Frequency = NULL, $SearchParameters = NULL)
37 # get our own database handle 40 # if search ID was provided 41 if ($SearchId !== NULL)
44 $this->SearchId = intval($SearchId);
46 # initialize our local copies of data 48 "SELECT * FROM SavedSearches " 49 .
"WHERE SearchId = ".$this->SearchId);
51 if ($this->DB->NumRowsSelected() == 0)
53 throw new Exception (
"Specified SearchId does not exist");
56 $this->Record = $this->DB->FetchRow();
58 # get our Search Parameters 60 $this->Record[
"SearchData"]);
62 # remove now redundant 'Data' from our record 63 unset ($this->Record[
"SearchData"]);
65 # update search details where provided 83 # add new saved search to database 84 $this->DB->Query(
"INSERT INTO SavedSearches" 85 .
" (SearchName, UserId, Frequency) VALUES (" 86 .
"'".addslashes($SearchName).
"', " 88 .intval($Frequency).
")");
90 # retrieve and save ID of new search locally 91 $this->SearchId = $this->DB->LastInsertId();
93 # populate our local data for this record 95 "SELECT * FROM SavedSearches " 96 .
"WHERE SearchId = ".$this->SearchId);
97 $this->Record = $this->DB->FetchRow();
99 if (!is_null($SearchParameters) && is_array($SearchParameters))
102 $Params->SetFromLegacyArray($SearchParameters);
103 $SearchParameters = $Params;
110 # signal event to allow modification of search parameters 111 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
112 "EVENT_FIELDED_SEARCH", array(
113 "SearchParameters" => $SearchParameters,
115 "SavedSearch" => $this));
120 $SearchResults = $SearchEngine->GroupedSearch(
121 $SearchParameters, 0, PHP_INT_MAX);
123 $NewItemIds = array_keys($SearchResults);
125 #Only allow resources the user can view 126 $NewItemIds = $RFactory->FilterNonViewableResources($NewItemIds, $EndUser);
128 # if search results were found 129 if (count($NewItemIds))
146 if (!is_null($NewSearchGroups))
149 $Params->SetFromLegacyArray($NewSearchGroups);
153 # return search parameters to caller 164 if (!is_null($NewParams))
169 $Data = $NewParams->Data();
172 "UPDATE SavedSearches SET SearchData = '". addslashes($Data).
"'" 173 .
" WHERE SearchId = ".$this->SearchId);
179 throw new Exception(
"NewParams must be a SearchParameterSet");
183 return clone $this->SearchParameters;
193 return $this->UpdateValue(
"SearchName", $NewValue);
202 return $this->SearchId;
212 return $this->UpdateValue(
"UserId", $NewValue);
222 return $this->UpdateValue(
"Frequency", $NewValue);
232 "UPDATE SavedSearches SET DateLastRun = NOW() " 233 .
"WHERE SearchId = ".$this->SearchId);
243 return $this->UpdateValue(
"DateLastRun", $NewValue);
252 $NewValue = implode(
",", $ArrayofMatchingIds);
253 $this->UpdateValue(
"LastMatchingIds", $NewValue);
262 return explode(
",", $this->DB->Query(
263 "SELECT LastMatchingIds FROM SavedSearches " 264 .
"WHERE SearchId = ".$this->SearchId,
"LastMatchingIds"));
273 return self::TranslateSearchGroupsToUrlParameters($this->
SearchGroups());
315 # assume that no parameters will be found 318 # for each group in parameters 320 foreach ($SearchGroups as $GroupIndex => $Group)
322 # if group holds single parameters 323 if ($GroupIndex ==
"MAIN")
325 # for each field within group 326 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
328 # add segment to URL for this field 329 if ($FieldName ==
"XXXKeywordXXX")
335 $Field = $Schema->GetFieldByName($FieldName);
336 $FieldId = $Field->Id();
338 if (is_array($Value))
340 $UrlPortion .=
"&F".$FieldId.
"=";
342 foreach ($Value as $SingleValue)
344 $ValueString .= $SingleValue.
" ";
346 $UrlPortion .= urlencode(trim($ValueString));
350 $UrlPortion .=
"&F".$FieldId.
"=".urlencode($Value);
356 # convert value based on field type 357 $FieldId = ($GroupIndex[0] ==
"X")
358 ? substr($GroupIndex, 1)
360 $Field = $Schema->GetField($FieldId);
361 $FieldName = $Field->Name();
362 $Values = self::TranslateValues($Field,
363 $Group[
"SearchStrings"][$FieldName],
364 "SearchGroup to Database");
368 foreach ($Values as $Value)
373 $UrlPortion .=
"&G".$FieldId.
"=".$Value;
377 $UrlPortion .=
"-".$Value;
383 # trim off any leading "&" 384 if (strlen($UrlPortion)) { $UrlPortion = substr($UrlPortion, 1); }
386 # return URL portion to caller 397 return self::TranslateSearchGroupsToUrlParameters($this->
SearchGroups());
408 # assume that no parameters will be found 409 $UrlPortion = array();
411 # for each group in parameters 413 foreach ($SearchGroups as $GroupIndex => $Group)
415 # if group holds single parameters 416 if ($GroupIndex ==
"MAIN")
418 # for each field within group 419 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
421 # add segment to URL for this field 422 if ($FieldName ==
"XXXKeywordXXX")
428 $Field = $Schema->GetFieldByName($FieldName);
429 $FieldId = $Field->Id();
431 if (is_array($Value))
434 foreach ($Value as $SingleValue)
436 $ValueString .= $SingleValue.
" ";
439 $UrlPortion[
"F".$FieldId] = urlencode(trim($ValueString));
443 $UrlPortion[
"F".$FieldId] = urlencode($Value);
449 # convert value based on field type 450 $FieldId = ($GroupIndex[0] ==
"X")
451 ? substr($GroupIndex, 1)
453 $Field = $Schema->GetField($FieldId);
454 $FieldName = $Field->Name();
455 $Values = self::TranslateValues($Field,
456 $Group[
"SearchStrings"][$FieldName],
457 "SearchGroup to Database");
463 foreach ($Values as $Value)
468 $UrlPortion[$LeadChar.$FieldId] = $Value;
472 $UrlPortion[$LeadChar.$FieldId] .=
"-".$Value;
478 # return URL portion to caller 489 # if URL segment was passed in instead of GET var array 490 if (is_string($GetVars))
492 $GetVars = ParseQueryString($GetVars);
495 # start with empty list of parameters 496 $SearchGroups = array();
499 $AllFields = $Schema->GetFields(NULL, NULL, TRUE);
501 foreach ($AllFields as $Field)
503 $FieldId = $Field->Id();
504 $FieldName = $Field->Name();
506 # if URL included literal value for this field 507 if (isset($GetVars[
"F".$FieldId]))
509 # retrieve value and add to search parameters 510 $SearchGroups[
"MAIN"][
"SearchStrings"][$FieldName] =
511 $GetVars[
"F".$FieldId];
514 # if URL included group value for this field 515 if (isset($GetVars[
"G".$FieldId]))
517 # retrieve and parse out values 518 $Values = explode(
"-", $GetVars[
"G".$FieldId]);
521 $Values = self::TranslateValues($Field, $Values,
522 "Database to SearchGroup");
524 # add values to searchgroups 525 $SearchGroups[$FieldId][
"SearchStrings"][$FieldName] = $Values;
528 # if URL included group value for this field 529 if (isset($GetVars[
"H".$FieldId]))
531 # retrieve and parse out values 532 $Values = explode(
"-", $GetVars[
"H".$FieldId]);
535 $Values = self::TranslateValues($Field, $Values,
536 "Database to SearchGroup");
538 # add values to searchgroups 539 $SearchGroups[
"X".$FieldId][
"SearchStrings"][$FieldName] = $Values;
543 # if keyword pseudo-field was included in URL 544 if (isset($GetVars[
"FK"]))
546 # retrieve value and add to search parameters 547 $SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"] = $GetVars[
"FK"];
551 foreach ($SearchGroups as $GroupIndex => $Group)
553 $SearchGroups[$GroupIndex][
"Logic"] = ($GroupIndex ==
"MAIN")
555 : (($GroupIndex[0] ==
"X")
559 # return parameters to caller 560 return $SearchGroups;
574 $IncludeHtml = TRUE, $StartWithBreak = TRUE, $TruncateLongWordsTo = 0)
577 $IncludeHtml, $StartWithBreak, $TruncateLongWordsTo);
592 $IncludeHtml = TRUE, $StartWithBreak = TRUE, $TruncateLongWordsTo = 0)
596 # start with empty description 599 # set characters used to indicate literal strings 600 $LiteralStart = $IncludeHtml ?
"<i>" :
"\"";
601 $LiteralEnd = $IncludeHtml ?
"</i>" :
"\"";
602 $LiteralBreak = $IncludeHtml ?
"<br>\n" :
"\n";
604 # if this is a simple keyword search 605 if (isset($SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"])
606 && (count($SearchGroups) == 1)
607 && (count($SearchGroups[
"MAIN"][
"SearchStrings"]) == 1))
609 # just use the search string 610 $Descrip .= $LiteralStart;
611 $Descrip .= defaulthtmlentities(
612 $SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"]);
613 $Descrip .= $LiteralEnd . $LiteralBreak;
617 # start description on a new line (if requested) 620 $Descrip .= $LiteralBreak;
623 # define list of phrases used to represent logical operators 624 $WordsForOperators = array(
626 ">" =>
"is greater than",
627 "<" =>
"is less than",
628 ">=" =>
"is at least",
629 "<=" =>
"is no more than",
633 # for each search group 634 foreach ($SearchGroups as $GroupIndex => $Group)
637 if ($GroupIndex ==
"MAIN")
639 # for each field in group 640 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
642 # determine wording based on operator 643 preg_match(
"/^[=><!]+/", $Value, $Matches);
644 if (count($Matches) && isset($WordsForOperators[$Matches[0]]))
646 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
647 $Wording = $WordsForOperators[$Matches[0]];
651 $Wording =
"contains";
654 # if field is psuedo-field 655 if ($FieldName ==
"XXXKeywordXXX")
657 # add criteria for psuedo-field 658 $Descrip .=
"Keyword ".$Wording.
" " 659 .$LiteralStart.htmlspecialchars($Value)
660 .$LiteralEnd.$LiteralBreak;
665 $Field = $Schema->GetFieldByName($FieldName);
668 # add criteria for field 669 $Descrip .= $Field->GetDisplayName().
" ".$Wording.
" " 670 .$LiteralStart.htmlspecialchars($Value)
671 .$LiteralEnd.$LiteralBreak;
678 # for each field in group 681 foreach ($Group[
"SearchStrings"] as $FieldName => $Values)
684 $Values = self::TranslateValues(
685 $FieldName, $Values,
"SearchGroup to Display");
689 foreach ($Values as $Value)
691 # determine wording based on operator 692 preg_match(
"/^[=><!]+/", $Value, $Matches);
693 $Operator = $Matches[0];
694 $Wording = $WordsForOperators[$Operator];
697 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
699 # add text to description 702 $Descrip .= $FieldName.
" ".$Wording.
" " 703 .$LiteralStart.htmlspecialchars($Value)
704 .$LiteralEnd.$LiteralBreak;
709 $Descrip .= ($IncludeHtml ?
710 " " :
" ")
711 .$LogicTerm.$Wording.
" ".$LiteralStart
712 .htmlspecialchars($Value).$LiteralEnd
721 # if caller requested that long words be truncated 722 if ($TruncateLongWordsTo > 4)
724 # break description into words 725 $Words = explode(
" ", $Descrip);
729 foreach ($Words as $Word)
731 # if word is longer than specified length 732 if (strlen(strip_tags($Word)) > $TruncateLongWordsTo)
734 # truncate word and add ellipsis 738 # add word to new description 739 $NewDescrip .=
" ".$Word;
742 # set description to new description 743 $Descrip = $NewDescrip;
746 # return description to caller 766 # start out assuming no fields are being searched 767 $FieldNames = array();
769 # for each search group defined 770 foreach ($SearchGroups as $GroupIndex => $Group)
772 # for each field in group 773 foreach ($Group[
"SearchStrings"] as $FieldName => $Values)
775 # add field name to list of fields being searched 776 $FieldNames[] = $FieldName;
780 # return list of fields being searched to caller 791 # define list with descriptions 793 self::SEARCHFREQ_NEVER =>
"Never",
794 self::SEARCHFREQ_HOURLY =>
"Hourly",
795 self::SEARCHFREQ_DAILY =>
"Daily",
796 self::SEARCHFREQ_WEEKLY =>
"Weekly",
797 self::SEARCHFREQ_BIWEEKLY =>
"Biweekly",
798 self::SEARCHFREQ_MONTHLY =>
"Monthly",
799 self::SEARCHFREQ_QUARTERLY =>
"Quarterly",
800 self::SEARCHFREQ_YEARLY =>
"Yearly",
803 # for each argument passed in 804 $Args = func_get_args();
805 foreach ($Args as $Arg)
807 # remove value from list 808 $FreqDescr = array_diff_key($FreqDescr, array($Arg =>
""));
811 # return list to caller 820 $this->DB->Query(
"DELETE FROM SavedSearches" 821 .
" WHERE SearchId = ".intval($this->SearchId));
825 # ---- PRIVATE INTERFACE ------------------------------------------------- 829 private $SearchGroups;
845 private static function TranslateValues($FieldOrFieldName, $Values, $TranslationType)
847 # start out assuming we won't find any values to translate 848 $ReturnValues = array();
850 # convert field name to field object if necessary 851 if (is_object($FieldOrFieldName))
853 $Field = $FieldOrFieldName;
859 $Field = $Schema->GetFieldByName($FieldOrFieldName);
862 # if incoming value is not an array 863 if (!is_array($Values))
865 # convert incoming value to an array 866 $Values = array($Values);
869 # for each incoming value 870 foreach ($Values as $Value)
872 switch ($TranslationType)
874 case "SearchGroup to Display":
875 # if field is Flag field 878 # translate value to true/false label and add leading operator 879 $ReturnValues[] = ($Value ==
"=1") ?
880 "=".$Field->FlagOnLabel() :
"=".$Field->FlagOffLabel();
882 elseif ($Field->Name() ==
"Cumulative Rating")
884 # translate numeric value to stars 885 $StarStrings = array(
892 preg_match(
"/[0-9]+$/", $Value, $Matches);
893 $Number = $Matches[0];
894 preg_match(
"/^[=><!]+/", $Value, $Matches);
895 $Operator = $Matches[0];
896 $ReturnValues[] = $Operator.$StarStrings[$Number];
901 $ReturnValues[] = $Value;
905 case "SearchGroup to Database":
906 # strip off leading operator on value 907 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
909 # look up index for value 913 # (for flag or number fields the value index is already 914 # what is used in SearchGroups) 917 $ReturnValues[] = $Value;
922 # (for user fields the value index is the user ID) 923 $User =
new CWUser(strval($Value));
926 $ReturnValues[] = $User->Id();
931 if (!isset($PossibleFieldValues))
933 $PossibleFieldValues = $Field->GetPossibleValues();
935 $NewValue = array_search($Value, $PossibleFieldValues);
936 if ($NewValue !== FALSE)
938 $ReturnValues[] = $NewValue;
943 $NewValue = $Field->GetIdForValue($Value);
944 if ($NewValue !== NULL)
946 $ReturnValues[] = $NewValue;
951 case "Database to SearchGroup":
952 # look up value for index 955 # (for flag fields the value index (0 or 1) is already 956 # what is used in Database) 959 $ReturnValues[] =
"=".$Value;
964 # (for flag fields the value index (0 or 1) is already 965 # what is used in Database) 969 $ReturnValues[] =
">=".$Value;
974 $User =
new CWUser(intval($Value));
977 $ReturnValues[] =
"=".$User->Get(
"UserName");
982 if (!isset($PossibleFieldValues))
984 $PossibleFieldValues = $Field->GetPossibleValues();
987 if (isset($PossibleFieldValues[$Value]))
989 $ReturnValues[] =
"=".$PossibleFieldValues[$Value];
994 $NewValue = $Field->GetValueForId($Value);
995 if ($NewValue !== NULL)
997 $ReturnValues[] =
"=".$NewValue;
1004 # return array of translated values to caller 1005 return $ReturnValues;
1010 # utility function for updating values in database 1017 private function UpdateValue($FieldName, $NewValue)
1019 return $this->DB->UpdateValue(
"SavedSearches", $FieldName, $NewValue,
1020 "SearchId = ".$this->SearchId, $this->Record);
1036 private $SearchParameters;
static TranslateUrlParametersToSearchGroups($GetVars)
Translate URL parameters to legacy search group array.
Set of parameters used to perform a search.
UpdateDateLastRun()
Update date this search was last run.
SQL database abstraction object with smart query caching.
GetSearchId()
Get search id.
static TranslateSearchGroupsToUrlParameterArray($SearchGroups)
Translate a search group array to an URL parameter array.
const SEARCHFREQ_QUARTERLY
UserId($NewValue=DB_NOVALUE)
Get/set user ID.
Frequency($NewValue=DB_NOVALUE)
Get/set search frequency.
const SEARCHFREQ_BIWEEKLY
static TranslateSearchGroupsToTextDescription($SearchGroups, $IncludeHtml=TRUE, $StartWithBreak=TRUE, $TruncateLongWordsTo=0)
Translate search group array into multi-line string describing search criteria.
DateLastRun($NewValue=DB_NOVALUE)
Get/set the date this search was last run.
static TranslateSearchGroupsToUrlParameters($SearchGroups)
Translate search group array into URL parameters (e.g.
GetSearchGroupsAsTextDescription($IncludeHtml=TRUE, $StartWithBreak=TRUE, $TruncateLongWordsTo=0)
Get multi-line string describing search criteria.
static NeatlyTruncateString($String, $MaxLength, $BreakAnywhere=FALSE)
Attempt to truncate a string as neatly as possible with respect to word breaks, punctuation, and HTML tags.
SearchGroups($NewSearchGroups=NULL)
Get/set search parameters from legacy array.
GetSearchFieldNames()
Get list of fields to be searched.
__construct($SearchId, $SearchName=NULL, $UserId=NULL, $Frequency=NULL, $SearchParameters=NULL)
Object constructor.
Delete()
Delete saved search.
SearchName($NewValue=DB_NOVALUE)
Get/set name of search.
GetSearchGroupsAsUrlParameterArray()
Get search groups as an URL parameter array.
GetSearchGroupsAsUrlParameters()
Get search groups as URL parameters (e.g.
LastMatches()
Return array of most recently matched ResourceIds for a search.
Factory for Resource objects.
CWIS-specific user class.
SearchParameters($NewParams=NULL)
Get/set search parameters.
static GetSearchFrequencyList()
Get array of possible search frequency descriptions.
static TranslateSearchGroupsToSearchFieldNames($SearchGroups)
Extract list of fields to be searched from search group array.
SaveLastMatches($ArrayofMatchingIds)
Save array of last matches.