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 # save frequency and user ID locally 94 $this->Record[
"SearchName"] = $SearchName;
95 $this->Record[
"UserId"] = $UserId;
96 $this->Record[
"Frequency"] = $Frequency;
98 if (!is_null($SearchParameters) && is_array($SearchParameters))
101 $Params->SetFromLegacyArray($SearchParameters);
102 $SearchParameters = $Params;
109 # signal event to allow modification of search parameters 110 $SignalResult = $GLOBALS[
"AF"]->SignalEvent(
111 "EVENT_FIELDED_SEARCH", array(
112 "SearchParameters" => $SearchParameters,
114 "SavedSearch" => $this));
119 $SearchResults = $SearchEngine->GroupedSearch(
120 $SearchParameters, 0, PHP_INT_MAX);
122 $NewItemIds = array_keys($SearchResults);
124 #Only allow resources the user can view 125 $NewItemIds = $RFactory->FilterNonViewableResources($NewItemIds, $EndUser);
127 # if search results were found 128 if (count($NewItemIds))
145 if (!is_null($NewSearchGroups))
148 $Params->SetFromLegacyArray($NewSearchGroups);
152 # return search parameters to caller 163 if (!is_null($NewParams))
168 $Data = $NewParams->Data();
171 "UPDATE SavedSearches SET SearchData = '". addslashes($Data).
"'" 172 .
" WHERE SearchId = ".$this->SearchId);
178 throw new Exception(
"NewParams must be a SearchParameterSet");
182 return clone $this->SearchParameters;
192 return $this->UpdateValue(
"SearchName", $NewValue);
201 return $this->SearchId;
211 return $this->UpdateValue(
"UserId", $NewValue);
221 return $this->UpdateValue(
"Frequency", $NewValue);
231 "UPDATE SavedSearches SET DateLastRun = NOW() " 232 .
"WHERE SearchId = ".$this->SearchId);
242 return $this->UpdateValue(
"DateLastRun", $NewValue);
251 $NewValue = implode(
",", $ArrayofMatchingIds);
252 $this->UpdateValue(
"LastMatchingIds", $NewValue);
261 return explode(
",", $this->DB->Query(
262 "SELECT LastMatchingIds FROM SavedSearches " 263 .
"WHERE SearchId = ".$this->SearchId,
"LastMatchingIds"));
272 return self::TranslateSearchGroupsToUrlParameters($this->
SearchGroups());
314 # assume that no parameters will be found 317 # for each group in parameters 319 foreach ($SearchGroups as $GroupIndex => $Group)
321 # if group holds single parameters 322 if ($GroupIndex ==
"MAIN")
324 # for each field within group 325 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
327 # add segment to URL for this field 328 if ($FieldName ==
"XXXKeywordXXX")
334 $Field = $Schema->GetFieldByName($FieldName);
335 $FieldId = $Field->Id();
337 if (is_array($Value))
339 $UrlPortion .=
"&F".$FieldId.
"=";
341 foreach ($Value as $SingleValue)
343 $ValueString .= $SingleValue.
" ";
345 $UrlPortion .= urlencode(trim($ValueString));
349 $UrlPortion .=
"&F".$FieldId.
"=".urlencode($Value);
355 # convert value based on field type 356 $FieldId = ($GroupIndex[0] ==
"X")
357 ? substr($GroupIndex, 1)
359 $Field = $Schema->GetField($FieldId);
360 $FieldName = $Field->Name();
361 $Values = self::TranslateValues($Field,
362 $Group[
"SearchStrings"][$FieldName],
363 "SearchGroup to Database");
367 foreach ($Values as $Value)
372 $UrlPortion .=
"&G".$FieldId.
"=".$Value;
376 $UrlPortion .=
"-".$Value;
382 # trim off any leading "&" 383 if (strlen($UrlPortion)) { $UrlPortion = substr($UrlPortion, 1); }
385 # return URL portion to caller 396 return self::TranslateSearchGroupsToUrlParameters($this->
SearchGroups());
407 # assume that no parameters will be found 408 $UrlPortion = array();
410 # for each group in parameters 412 foreach ($SearchGroups as $GroupIndex => $Group)
414 # if group holds single parameters 415 if ($GroupIndex ==
"MAIN")
417 # for each field within group 418 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
420 # add segment to URL for this field 421 if ($FieldName ==
"XXXKeywordXXX")
427 $Field = $Schema->GetFieldByName($FieldName);
428 $FieldId = $Field->Id();
430 if (is_array($Value))
433 foreach ($Value as $SingleValue)
435 $ValueString .= $SingleValue.
" ";
438 $UrlPortion[
"F".$FieldId] = urlencode(trim($ValueString));
442 $UrlPortion[
"F".$FieldId] = urlencode($Value);
448 # convert value based on field type 449 $FieldId = ($GroupIndex[0] ==
"X")
450 ? substr($GroupIndex, 1)
452 $Field = $Schema->GetField($FieldId);
453 $FieldName = $Field->Name();
454 $Values = self::TranslateValues($Field,
455 $Group[
"SearchStrings"][$FieldName],
456 "SearchGroup to Database");
462 foreach ($Values as $Value)
467 $UrlPortion[$LeadChar.$FieldId] = $Value;
471 $UrlPortion[$LeadChar.$FieldId] .=
"-".$Value;
477 # return URL portion to caller 488 # if URL segment was passed in instead of GET var array 489 if (is_string($GetVars))
491 $GetVars = ParseQueryString($GetVars);
494 # start with empty list of parameters 495 $SearchGroups = array();
498 $AllFields = $Schema->GetFields(NULL, NULL, TRUE);
500 foreach ($AllFields as $Field)
502 $FieldId = $Field->Id();
503 $FieldName = $Field->Name();
505 # if URL included literal value for this field 506 if (isset($GetVars[
"F".$FieldId]))
508 # retrieve value and add to search parameters 509 $SearchGroups[
"MAIN"][
"SearchStrings"][$FieldName] =
510 $GetVars[
"F".$FieldId];
513 # if URL included group value for this field 514 if (isset($GetVars[
"G".$FieldId]))
516 # retrieve and parse out values 517 $Values = explode(
"-", $GetVars[
"G".$FieldId]);
520 $Values = self::TranslateValues($Field, $Values,
521 "Database to SearchGroup");
523 # add values to searchgroups 524 $SearchGroups[$FieldId][
"SearchStrings"][$FieldName] = $Values;
527 # if URL included group value for this field 528 if (isset($GetVars[
"H".$FieldId]))
530 # retrieve and parse out values 531 $Values = explode(
"-", $GetVars[
"H".$FieldId]);
534 $Values = self::TranslateValues($Field, $Values,
535 "Database to SearchGroup");
537 # add values to searchgroups 538 $SearchGroups[
"X".$FieldId][
"SearchStrings"][$FieldName] = $Values;
542 # if keyword pseudo-field was included in URL 543 if (isset($GetVars[
"FK"]))
545 # retrieve value and add to search parameters 546 $SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"] = $GetVars[
"FK"];
550 foreach ($SearchGroups as $GroupIndex => $Group)
552 $SearchGroups[$GroupIndex][
"Logic"] = ($GroupIndex ==
"MAIN")
554 : (($GroupIndex[0] ==
"X")
558 # return parameters to caller 559 return $SearchGroups;
573 $IncludeHtml = TRUE, $StartWithBreak = TRUE, $TruncateLongWordsTo = 0)
576 $IncludeHtml, $StartWithBreak, $TruncateLongWordsTo);
591 $IncludeHtml = TRUE, $StartWithBreak = TRUE, $TruncateLongWordsTo = 0)
595 # start with empty description 598 # set characters used to indicate literal strings 599 $LiteralStart = $IncludeHtml ?
"<i>" :
"\"";
600 $LiteralEnd = $IncludeHtml ?
"</i>" :
"\"";
601 $LiteralBreak = $IncludeHtml ?
"<br>\n" :
"\n";
603 # if this is a simple keyword search 604 if (isset($SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"])
605 && (count($SearchGroups) == 1)
606 && (count($SearchGroups[
"MAIN"][
"SearchStrings"]) == 1))
608 # just use the search string 609 $Descrip .= $LiteralStart;
610 $Descrip .= defaulthtmlentities(
611 $SearchGroups[
"MAIN"][
"SearchStrings"][
"XXXKeywordXXX"]);
612 $Descrip .= $LiteralEnd . $LiteralBreak;
616 # start description on a new line (if requested) 619 $Descrip .= $LiteralBreak;
622 # define list of phrases used to represent logical operators 623 $WordsForOperators = array(
625 ">" =>
"is greater than",
626 "<" =>
"is less than",
627 ">=" =>
"is at least",
628 "<=" =>
"is no more than",
632 # for each search group 633 foreach ($SearchGroups as $GroupIndex => $Group)
636 if ($GroupIndex ==
"MAIN")
638 # for each field in group 639 foreach ($Group[
"SearchStrings"] as $FieldName => $Value)
641 # determine wording based on operator 642 preg_match(
"/^[=><!]+/", $Value, $Matches);
643 if (count($Matches) && isset($WordsForOperators[$Matches[0]]))
645 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
646 $Wording = $WordsForOperators[$Matches[0]];
650 $Wording =
"contains";
653 # if field is psuedo-field 654 if ($FieldName ==
"XXXKeywordXXX")
656 # add criteria for psuedo-field 657 $Descrip .=
"Keyword ".$Wording.
" " 658 .$LiteralStart.htmlspecialchars($Value)
659 .$LiteralEnd.$LiteralBreak;
664 $Field = $Schema->GetFieldByName($FieldName);
667 # add criteria for field 668 $Descrip .= $Field->GetDisplayName().
" ".$Wording.
" " 669 .$LiteralStart.htmlspecialchars($Value)
670 .$LiteralEnd.$LiteralBreak;
677 # for each field in group 680 foreach ($Group[
"SearchStrings"] as $FieldName => $Values)
683 $Values = self::TranslateValues(
684 $FieldName, $Values,
"SearchGroup to Display");
688 foreach ($Values as $Value)
690 # determine wording based on operator 691 preg_match(
"/^[=><!]+/", $Value, $Matches);
692 $Operator = $Matches[0];
693 $Wording = $WordsForOperators[$Operator];
696 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
698 # add text to description 701 $Descrip .= $FieldName.
" ".$Wording.
" " 702 .$LiteralStart.htmlspecialchars($Value)
703 .$LiteralEnd.$LiteralBreak;
708 $Descrip .= ($IncludeHtml ?
709 " " :
" ")
710 .$LogicTerm.$Wording.
" ".$LiteralStart
711 .htmlspecialchars($Value).$LiteralEnd
720 # if caller requested that long words be truncated 721 if ($TruncateLongWordsTo > 4)
723 # break description into words 724 $Words = explode(
" ", $Descrip);
728 foreach ($Words as $Word)
730 # if word is longer than specified length 731 if (strlen(strip_tags($Word)) > $TruncateLongWordsTo)
733 # truncate word and add ellipsis 734 $Word = NeatlyTruncateString($Word, $TruncateLongWordsTo - 3);
737 # add word to new description 738 $NewDescrip .=
" ".$Word;
741 # set description to new description 742 $Descrip = $NewDescrip;
745 # return description to caller 765 # start out assuming no fields are being searched 766 $FieldNames = array();
768 # for each search group defined 769 foreach ($SearchGroups as $GroupIndex => $Group)
771 # for each field in group 772 foreach ($Group[
"SearchStrings"] as $FieldName => $Values)
774 # add field name to list of fields being searched 775 $FieldNames[] = $FieldName;
779 # return list of fields being searched to caller 790 # define list with descriptions 792 self::SEARCHFREQ_NEVER =>
"Never",
793 self::SEARCHFREQ_HOURLY =>
"Hourly",
794 self::SEARCHFREQ_DAILY =>
"Daily",
795 self::SEARCHFREQ_WEEKLY =>
"Weekly",
796 self::SEARCHFREQ_BIWEEKLY =>
"Bi-Weekly",
797 self::SEARCHFREQ_MONTHLY =>
"Monthly",
798 self::SEARCHFREQ_QUARTERLY =>
"Quarterly",
799 self::SEARCHFREQ_YEARLY =>
"Yearly",
802 # for each argument passed in 803 $Args = func_get_args();
804 foreach ($Args as $Arg)
806 # remove value from list 807 $FreqDescr = array_diff_key($FreqDescr, array($Arg =>
""));
810 # return list to caller 819 $this->DB->Query(
"DELETE FROM SavedSearches" 820 .
" WHERE SearchId = ".intval($this->SearchId));
824 # ---- PRIVATE INTERFACE ------------------------------------------------- 828 private $SearchGroups;
844 private static function TranslateValues($FieldOrFieldName, $Values, $TranslationType)
846 # start out assuming we won't find any values to translate 847 $ReturnValues = array();
849 # convert field name to field object if necessary 850 if (is_object($FieldOrFieldName))
852 $Field = $FieldOrFieldName;
858 $Field = $Schema->GetFieldByName($FieldOrFieldName);
861 # if incoming value is not an array 862 if (!is_array($Values))
864 # convert incoming value to an array 865 $Values = array($Values);
868 # for each incoming value 869 foreach ($Values as $Value)
871 switch ($TranslationType)
873 case "SearchGroup to Display":
874 # if field is Flag field 877 # translate value to true/false label and add leading operator 878 $ReturnValues[] = ($Value ==
"=1") ?
879 "=".$Field->FlagOnLabel() :
"=".$Field->FlagOffLabel();
881 elseif ($Field->Name() ==
"Cumulative Rating")
883 # translate numeric value to stars 884 $StarStrings = array(
891 preg_match(
"/[0-9]+$/", $Value, $Matches);
892 $Number = $Matches[0];
893 preg_match(
"/^[=><!]+/", $Value, $Matches);
894 $Operator = $Matches[0];
895 $ReturnValues[] = $Operator.$StarStrings[$Number];
900 $ReturnValues[] = $Value;
904 case "SearchGroup to Database":
905 # strip off leading operator on value 906 $Value = preg_replace(
"/^[=><!]+/",
"", $Value);
908 # look up index for value 912 # (for flag or number fields the value index is already 913 # what is used in SearchGroups) 916 $ReturnValues[] = $Value;
921 # (for user fields the value index is the user ID) 922 $User =
new CWUser(strval($Value));
925 $ReturnValues[] = $User->Id();
930 if (!isset($PossibleFieldValues))
932 $PossibleFieldValues = $Field->GetPossibleValues();
934 $NewValue = array_search($Value, $PossibleFieldValues);
935 if ($NewValue !== FALSE)
937 $ReturnValues[] = $NewValue;
942 $NewValue = $Field->GetIdForValue($Value);
943 if ($NewValue !== NULL)
945 $ReturnValues[] = $NewValue;
950 case "Database to SearchGroup":
951 # look up value for index 954 # (for flag fields the value index (0 or 1) is already 955 # what is used in Database) 958 $ReturnValues[] =
"=".$Value;
963 # (for flag fields the value index (0 or 1) is already 964 # what is used in Database) 968 $ReturnValues[] =
">=".$Value;
973 $User =
new CWUser(intval($Value));
976 $ReturnValues[] =
"=".$User->Get(
"UserName");
981 if (!isset($PossibleFieldValues))
983 $PossibleFieldValues = $Field->GetPossibleValues();
986 if (isset($PossibleFieldValues[$Value]))
988 $ReturnValues[] =
"=".$PossibleFieldValues[$Value];
993 $NewValue = $Field->GetValueForId($Value);
994 if ($NewValue !== NULL)
996 $ReturnValues[] =
"=".$NewValue;
1003 # return array of translated values to caller 1004 return $ReturnValues;
1009 # utility function for updating values in database 1016 private function UpdateValue($FieldName, $NewValue)
1018 return $this->DB->UpdateValue(
"SavedSearches", $FieldName, $NewValue,
1019 "SearchId = ".$this->SearchId, $this->Record);
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.
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.