CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

SearchParameterSet.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SearchParameterSet.php
4 #
5 # Part of the ScoutLib application support library
6 # Copyright 2015-2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu
8 #
9
13 class SearchParameterSet
14 {
15
16 # ---- SETUP / CONFIGURATION ---------------------------------------------
17 /*@(*/
18
26 public function __construct($Data = NULL)
27 {
28 # if set data supplied
29 if ($Data !== NULL)
30 {
31 # set internal values from data
32 $this->LoadFromData($Data);
33 }
34 }
35
40 public function __clone()
41 {
42 foreach ($this->Subgroups as &$Group)
43 {
44 $Group = clone $Group;
45 }
46 }
47
55 public static function SetCanonicalFieldFunction($Func)
56 {
57 if (is_callable($Func))
58 {
59 self::$CanonicalFieldFunction = $Func;
60 }
61 else
62 {
63 throw new InvalidArgumentException("Invalid function supplied.");
64 }
65 }
66
74 public static function SetPrintableFieldFunction($Func)
75 {
76 if (is_callable($Func))
77 {
78 self::$PrintableFieldFunction = $Func;
79 }
80 else
81 {
82 throw new InvalidArgumentException("Invalid function supplied.");
83 }
84 }
85
91 /*@)*/
92 # ---- SET CONSTRUCTION ---------------------------------------------------
93 /*@(*/
94
105 public function AddParameter($SearchStrings, $Field = NULL)
106 {
107 # normalize field value if supplied
108 $Field = self::NormalizeField($Field);
109
110 # make sure search strings are an array
111 if (!is_array($SearchStrings))
112 { $SearchStrings = array($SearchStrings); }
113
114 # for each search string
115 foreach ($SearchStrings as $String)
116 {
117 # if field specified
118 if ($Field !== NULL)
119 {
120 # add strings to search values for field
121 $this->SearchStrings[$Field][] = $String;
122 }
123 else
124 {
125 # add strings to keyword search values
126 $this->KeywordSearchStrings[] = $String;
127 }
128 }
129 }
130
139 public function RemoveParameter($SearchStrings, $Field = NULL)
140 {
141 # normalize field value if supplied
142 $Field = self::NormalizeField($Field);
143
144 # if search strings specified
145 if ($SearchStrings != NULL)
146 {
147 # make sure search strings are an array
148 if (!is_array($SearchStrings))
149 { $SearchStrings = array($SearchStrings); }
150
151 # for each search string
152 foreach ($SearchStrings as $String)
153 {
154 # if field specified
155 if ($Field !== NULL)
156 {
157 # if there are search parameters for this field
158 if (isset($this->SearchStrings[$Field]))
159 {
160 # remove any matching search parameters
161 $NewSearchStrings = array();
162 foreach ($this->SearchStrings[$Field] as $Value)
163 {
164 if ($Value != $String)
165 {
166 $NewSearchStrings[] = $Value;
167 }
168 }
169 if (count($NewSearchStrings))
170 {
171 $this->SearchStrings[$Field] = $NewSearchStrings;
172 }
173 else
174 {
175 unset($this->SearchStrings[$Field]);
176 }
177 }
178 }
179 else
180 {
181 # remove any matching keyword search parameters
182 $NewSearchStrings = array();
183 foreach ($this->KeywordSearchStrings as $Value)
184 {
185 if ($Value != $String)
186 {
187 $NewSearchStrings[] = $Value;
188 }
189 }
190 $this->KeywordSearchStrings = $NewSearchStrings;
191 }
192 }
193 }
194 else
195 {
196 # if field specified
197 if ($Field !== NULL)
198 {
199 # clear any search strings for this field
200 if (isset($this->SearchStrings[$Field]))
201 {
202 unset($this->SearchStrings[$Field]);
203 }
204 }
205 else
206 {
207 # clear all keyword search parameters
208 $this->KeywordSearchStrings = array();
209 }
210 }
211
212 # for each parameter subgroup
213 $NewSubgroups = array();
214 foreach ($this->Subgroups as $Group)
215 {
216 # remove parameter from subgroup
217 $Group->RemoveParameter($SearchStrings, $Field);
218
219 # if the subgroup is not empty
220 if ($Group->ParameterCount())
221 {
222 # keep subgroup
223 $NewSubgroups[] = $Group;
224 }
225 }
226 $this->Subgroups = $NewSubgroups;
227 }
228
236 public function Logic($NewValue = NULL)
237 {
238 # if new value supplied
239 if ($NewValue !== NULL)
240 {
241 # normalize value
242 $NormValue = ($NewValue == SearchEngine::LOGIC_OR)
243 ? "OR"
244 : (($NewValue == SearchEngine::LOGIC_AND)
245 ? "AND"
246 : strtoupper($NewValue));
247
248 # error out if value appears invalid
249 if (($NormValue !== "AND") && ($NormValue !== "OR"))
250 {
251 throw new InvalidArgumentException("New logic setting"
252 ." is invalid (".$NewValue.").");
253 }
254
255 # save new setting
256 $this->Logic = $NormValue;
257 }
258
259 # return current logic setting to caller
260 return $this->Logic;
261 }
262
271 public function ItemTypes($ItemTypes = FALSE)
272 {
273 if ($ItemTypes !== FALSE)
274 {
275 if (!is_array($ItemTypes))
276 {
277 $ItemTypes = array($ItemTypes);
278 }
279 $this->ItemTypes = $ItemTypes;
280 }
281 return $this->ItemTypes;
282 }
283
288 public function AddSet(SearchParameterSet $Set)
289 {
290 if ($Set->ParameterCount())
291 {
292 $this->Subgroups[] = $Set;
293 }
294 }
295
296
297 /*@)*/
298 # ---- DATA RETRIEVAL -----------------------------------------------------
299 /*@(*/
300
305 public function ParameterCount()
306 {
307 $Count = count($this->KeywordSearchStrings);
308 foreach ($this->SearchStrings as $Field => $Strings)
309 {
310 $Count += count($Strings);
311 }
312 foreach ($this->Subgroups as $Group)
313 {
314 $Count += $Group->ParameterCount();
315 }
316 return $Count;
317 }
318
326 public function GetSearchStrings($IncludeSubgroups = FALSE)
327 {
328 $SearchStrings = $this->SearchStrings;
329 if ($IncludeSubgroups)
330 {
331 foreach ($this->Subgroups as $Group)
332 {
333 $SubStrings = $Group->GetSearchStrings(TRUE);
334 foreach ($SubStrings as $Field => $Strings)
335 {
336 if (isset($SearchStrings[$Field]))
337 {
338 $SearchStrings[$Field] = array_merge(
339 $SearchStrings[$Field], $Strings);
340 }
341 else
342 {
343 $SearchStrings[$Field] = $Strings;
344 }
345 }
346 }
347 }
348 return $SearchStrings;
349 }
350
359 public function GetSearchStringsForField($Field, $IncludeSubgroups = TRUE)
360 {
361 # normalize field value
362 $Field = self::NormalizeField($Field);
363
364 # start with our string values
365 $Strings = isset($this->SearchStrings[$Field])
366 ? $this->SearchStrings[$Field] : array();
367
368 # if strings from subgroups should also be returned
369 if ($IncludeSubgroups)
370 {
371 # for each subgroup
372 foreach ($this->Subgroups as $Group)
373 {
374 # add any strings from that subgroup
375 $Strings = array_merge($Strings,
376 $Group->GetSearchStringsForField($Field));
377 }
378 }
379
380 # return all strings found to caller
381 return $Strings;
382 }
383
388 public function GetKeywordSearchStrings()
389 {
390 return $this->KeywordSearchStrings;
391 }
392
397 public function GetSubgroups()
398 {
399 return $this->Subgroups;
400 }
401
406 public function GetFields()
407 {
408 # retrieve our fields
409 $Fields = array_keys($this->SearchStrings);
410
411 # for each subgroup
412 foreach ($this->Subgroups as $Group)
413 {
414 # add fields from subgroup to the list
415 $Fields = array_merge($Fields, $Group->GetFields());
416 }
417
418 # filter out duplicates and sort to ensure consistency
419 $Fields = array_unique($Fields);
420 sort($Fields);
421
422 # return list of field identifiers to caller
423 return $Fields;
424 }
425
426
427 /*@)*/
428 # ---- DATA TRANSLATION ---------------------------------------------------
429 /*@(*/
430
441 public function Data($NewValue = NULL)
442 {
443 # if new data supplied
444 if ($NewValue !== NULL)
445 {
446 # unpack set data and load
447 $this->LoadFromData($NewValue);
448 }
449
450 # serialize current data and return to caller
451 $Data = array();
452 if ($this->Logic !== "AND") { $Data["Logic"] = $this->Logic; }
453 if (count($this->SearchStrings))
454 { $Data["SearchStrings"] = $this->SearchStrings; }
455 if (count($this->KeywordSearchStrings))
456 {
457 $Data["KeywordSearchStrings"] = $this->KeywordSearchStrings;
458 }
459 if (count($this->Subgroups))
460 {
461 foreach ($this->Subgroups as $Subgroup)
462 {
463 $Data["Subgroups"][] = $Subgroup->Data();
464 }
465 }
466 return serialize($Data);
467 }
468
475 public function UrlParameters($NewValue = NULL)
476 {
477 # if new value supplied
478 if ($NewValue !== NULL)
479 {
480 # set new parameters
481 $this->SetFromUrlParameters($NewValue);
482 }
483
484 # get existing search parameters as URL parameters
485 $Params = $this->GetAsUrlParameters();
486
487 # sort parameters by parameter name to normalize result
488 ksort($Params);
489
490 # return parameters to caller
491 return $Params;
492 }
493
500 public function UrlParameterString($NewValue = NULL)
501 {
502 # get/set parameters
503 $Params = $this->UrlParameters($NewValue);
504
505 # combine values into string
506 $ParamString = "";
507 $Separator = "";
508 foreach ($Params as $Index => $Value)
509 {
510 $ParamString .= $Separator.$Index."=".urlencode($Value);
511 $Separator = "&";
512 }
513
514 # return string to caller
515 return $ParamString;
516 }
517
529 public function TextDescription($IncludeHtml = TRUE, $StartWithBreak = TRUE,
530 $TruncateLongWordsTo = 0, $Indent = "")
531 {
532 # define list of phrases used to represent logical operators
533 $OperatorPhrases = array(
534 "=" => "is",
535 "==" => "is",
536 ">" => "is greater than",
537 "<" => "is less than",
538 ">=" => "is at least",
539 "<=" => "is no more than",
540 "!" => "is not",
541 "!=" => "is not",
542 "^" => "begins with",
543 "$" => "ends with",
544 "@" => "was last modified on or after",
545 "@>" => "was last modified after",
546 "@>=" => "was last modified on or after",
547 "@<" => "was last modified before",
548 "@<=" => "was last modified on or before",
549 );
550 $AgoOperatorPhrases = array(
551 "@>" => "was last modified more than",
552 "@>=" => "was last modified at least or more than",
553 "@<" => "was last modified less than",
554 "@<=" => "was last modified at most or less than",
555 );
556
557 # set characters used to indicate literal strings
558 $LiteralStart = $IncludeHtml ? "<i>" : "\"";
559 $LiteralEnd = $IncludeHtml ? "</i>" : "\"";
560 $LiteralBreak = $IncludeHtml ? "<br>\n" : "\n";
561 $Indent .= $IncludeHtml ? "&nbsp;&nbsp;&nbsp;&nbsp;" : " ";
562
563 # for each keyword search string
564 $Descriptions = array();
565 foreach ($this->KeywordSearchStrings as $SearchString)
566 {
567 # escape search string if appropriate
568 if ($IncludeHtml)
569 {
570 $SearchString = defaulthtmlentities($SearchString);
571 }
572
573 # add string to list of descriptions
574 $Descriptions[] = $LiteralStart.$SearchString.$LiteralEnd;
575 }
576
577 # for each field with search strings
578 foreach ($this->SearchStrings as $FieldId => $SearchStrings)
579 {
580 # retrieve field name
581 $FieldName = call_user_func(self::$PrintableFieldFunction, $FieldId);
582
583 # for each search string
584 foreach ($SearchStrings as $SearchString)
585 {
586 # extract operator from search string
587 $MatchResult = preg_match('/^([=><!^$@]+)(.+)/',
588 $SearchString, $Matches);
589
590 # determine operator phrase
591 if (($MatchResult == 1) && isset($OperatorPhrases[$Matches[1]]))
592 {
593 if (isset($AgoOperatorPhrases[$Matches[1]])
594 && strstr($SearchString, "ago"))
595 {
596 $OpPhrase = $AgoOperatorPhrases[$Matches[1]];
597 }
598 else
599 {
600 $OpPhrase = $OperatorPhrases[$Matches[1]];
601 }
602 $SearchString = $Matches[2];
603 }
604 else
605 {
606 $OpPhrase = "contains";
607 }
608
609 # escape field name and search string if appropriate
610 if ($IncludeHtml)
611 {
612 $FieldName = defaulthtmlentities($FieldName);
613 $SearchString = defaulthtmlentities($SearchString);
614 }
615
616 # assemble field and operator and value into description
617 $Descriptions[] = $FieldName." ".$OpPhrase." "
618 .$LiteralStart.$SearchString.$LiteralEnd;
619 }
620 }
621
622 # for each subgroup
623 foreach ($this->Subgroups as $Subgroup)
624 {
625 # retrieve description for subgroup
626 if ($Subgroup->ParameterCount() == 1)
627 {
628 $Descriptions[] = $Subgroup->TextDescription($IncludeHtml,
629 $StartWithBreak, $TruncateLongWordsTo, $Indent);
630 }
631 elseif ($Subgroup->ParameterCount() > 1)
632 {
633 $Descriptions[] = "(".$Subgroup->TextDescription($IncludeHtml,
634 $StartWithBreak, $TruncateLongWordsTo, $Indent).")";
635 }
636 }
637
638 # join descriptions with appropriate conjunction
639 $Descrip = join($LiteralBreak.$Indent." ".strtolower($this->Logic)." ",
640 $Descriptions);
641
642 # if caller requested that long words be truncated
643 if ($TruncateLongWordsTo > 4)
644 {
645 # break description into words
646 $Words = explode(" ", $Descrip);
647
648 # for each word
649 $NewDescrip = "";
650 foreach ($Words as $Word)
651 {
652 # if word is longer than specified length
653 if (strlen(strip_tags($Word)) > $TruncateLongWordsTo)
654 {
655 # truncate word and add ellipsis
656 $Word = StdLib::NeatlyTruncateString($Word, $TruncateLongWordsTo - 3);
657 }
658
659 # add word to new description
660 $NewDescrip .= " ".$Word;
661 }
662
663 # set description to new description
664 $Descrip = $NewDescrip;
665 }
666
667 if (isset(self::$TextDescriptionFilterFunction))
668 {
669 $Descrip = call_user_func_array(
670 self::$TextDescriptionFilterFunction,
671 [$Descrip]);
672 }
673
674 # return description to caller
675 return $Descrip;
676 }
677
678
679 /*@)*/
680 # ---- UTILITY METHODS ----------------------------------------------------
681 /*@(*/
682
688 public function ReplaceSearchString($Pattern, $Replacement)
689 {
690 # modify our fielded search strings
691 foreach ($this->SearchStrings as $Field => $Strings)
692 {
693 $this->SearchStrings[$Field] =
694 preg_replace($Pattern, $Replacement, $Strings);
695 }
696
697 # modify our keyword search strings
698 if (count($this->KeywordSearchStrings))
699 {
700 $this->KeywordSearchStrings =
701 preg_replace($Pattern, $Replacement, $this->KeywordSearchStrings);
702 }
703
704 # modify any subgroups
705 foreach ($this->Subgroups as $Group)
706 {
707 $Group->ReplaceSearchString($Pattern, $Replacement);
708 }
709 }
710
711
712 /*@)*/
713 # ---- BACKWARD COMPATIBILITY ---------------------------------------------
714 /*@(*/
715
724 public function GetAsLegacyArray()
725 {
726 $Legacy = array();
727
728 $Group = $this->ConvertToLegacyGroup();
729 if (count($Group))
730 {
731 $Legacy["MAIN"] = $Group;
732 }
733
734 # for each subgroup
735 foreach ($this->Subgroups as $Subgroup)
736 {
737 # skip empty search groups
738 if (count($Subgroup->SearchStrings)==0)
739 {
740 continue;
741 }
742
743 $SubLegacy = $Subgroup->ConvertToLegacyGroup();
744
745 # give an index based on the FieldId of the first
746 # element in the SearchStrings
747 $FieldId = call_user_func(
748 self::$CanonicalFieldFunction,
749 current(array_keys($SubLegacy["SearchStrings"])) );
750
751 # add groups from legacy array to our array
752 if (!isset($Legacy[$FieldId]))
753 {
754 $Legacy[$FieldId] = $SubLegacy;
755 }
756 else
757 {
758 $Num = count($Legacy[$FieldId]);
759 $Legacy[$FieldId."-".$Num] = $SubLegacy;
760 }
761
762 if (count($Subgroup->Subgroups))
763 {
764 throw new Exception(
765 "Attempt to convert SearchParameterSet containing nested subgroups "
766 ."to legacy format");
767 }
768 }
769
770 # return array to caller
771 return $Legacy;
772 }
773
778 public function SetFromLegacyArray($SearchGroups)
779 {
780 # clear current settings
781 $this->KeywordSearchStrings = array();
782 $this->SearchStrings = array();
783 $this->Subgroups = array();
784
785 # iterate over legacy search groups
786 foreach ($SearchGroups as $GroupId => $SearchGroup)
787 {
788 if ($GroupId == "MAIN")
789 {
790 # add terms from the main search group to ourself
791 $this->LoadFromLegacyGroup($SearchGroup);
792 }
793 else
794 {
795 # create subgroups for other groups
796 $Subgroup = new SearchParameterSet();
797 $Subgroup->LoadFromLegacyGroup($SearchGroup);
798
799 # add any non-empty groups
800 if ($Subgroup->ParameterCount())
801 {
802 $this->AddSet($Subgroup);
803 }
804 }
805 }
806 }
807
812 public function SetFromLegacyUrl($ParameterString)
813 {
814 # clear current settings
815 $this->KeywordSearchStrings = array();
816 $this->SearchStrings = array();
817 $this->Subgroups = array();
818
819 # extact array of parameters from passed string
820 $GetVars = ParseQueryString($ParameterString);
821
822 # iterate over the provided parameters
823 foreach ($GetVars as $Key => $Val)
824 {
825 # if this param gives search information
826 if (preg_match("/^([FGH])(K|[0-9]+)$/", $Key, $Matches))
827 {
828 # extract what kind of search it was which field
829 $Type = $Matches[1];
830 $FieldId = $Matches[2];
831
832 # for 'contains' searches
833 if ($Type == "F")
834 {
835 # add this to our search strings
836 $this->AddParameter( $Val,
837 ($FieldId == "K" ? NULL : $FieldId) );
838 }
839 else
840 {
841 # otherwise, create a subgroup for this parameter
842 $Subgroup = new SearchParameterSet();
843
844 # set logic based on the search type
845 $Subgroup->Logic($Type=="H" ? "AND" : "OR");
846
847 # extract the values and add them to a subgroup
848 $Values = explode("-", $Val);
849 $Subgroup->AddParameter(
850 self::TranslateLegacySearchValues($FieldId, $Values),
851 $FieldId );
852
853 # if subgroup was non-empty, slurp it up
854 if ($Subgroup->ParameterCount())
855 {
856 $this->AddSet($Subgroup);
857 }
858 }
859 }
860 }
861 }
862
868 public static function IsLegacyUrl($ParameterString)
869 {
870 $QueryVars = ParseQueryString($ParameterString);
871
872 return (array_key_exists("Q", $QueryVars) &&
873 $QueryVars["Q"] == "Y") ? TRUE : FALSE ;
874 }
875
881 public static function ConvertLegacyUrl($ParameterString)
882 {
883 $SearchParams = new SearchParameterSet();
884 $SearchParams->SetFromLegacyUrl($ParameterString);
885
886 return $SearchParams->UrlParameterString();
887 }
888
895 public static function SetLegacyUrlTranslationFunction($Func)
896 {
897 if (is_callable($Func))
898 {
899 self::$LegacyUrlTranslationFunction = $Func;
900 }
901 else
902 {
903 throw new InvalidArgumentException("Invalid function supplied.");
904 }
905 }
906
914 public static function SetTextDescriptionFilterFunction($Func)
915 {
916 if (is_callable($Func))
917 {
918 self::$TextDescriptionFilterFunction = $Func;
919 }
920 else
921 {
922 throw new InvalidArgumentException("Invalid function supplied.");
923 }
924 }
925
932 public static function TranslateLegacySearchValues($Field, $Values)
933 {
934 if (($Field !== NULL) && isset(self::$LegacyUrlTranslationFunction))
935 {
936 $Values = call_user_func(self::$LegacyUrlTranslationFunction,
937 $Field, $Values);
938 }
939 return $Values;
940 }
941
942 /*@)*/
943 # ---- PRIVATE INTERFACE -------------------------------------------------
944
945 private $KeywordSearchStrings = array();
946 private $ItemTypes = NULL;
947 private $Logic = self::DEFAULT_LOGIC;
948 private $SearchStrings = array();
949 private $Subgroups = array();
950
951 static private $CanonicalFieldFunction;
952 static private $PrintableFieldFunction;
953 static private $LegacyUrlTranslationFunction;
954 static private $TextDescriptionFilterFunction;
955 static private $UrlParameterPrefix = "F";
956
957 const DEFAULT_LOGIC = "AND";
958 const URL_KEYWORDFREE_RANGE = "A-JL-Z";
959 const URL_KEYWORD_INDICATOR = "K";
960 const URL_LOGIC_INDICATOR = "00";
961
967 private function LoadFromData($Serialized)
968 {
969 # unpack new data
970 $Data = unserialize($Serialized);
971 if (!is_array($Data))
972 {
973 throw new InvalidArgumentException("Incoming set data"
974 ." appears invalid.");
975 }
976
977 # load logic
978 $this->Logic = isset($Data["Logic"]) ? $Data["Logic"] : "AND";
979
980 # load search strings
981 $this->SearchStrings = isset($Data["SearchStrings"])
982 ? $Data["SearchStrings"] : array();
983 $this->KeywordSearchStrings = isset($Data["KeywordSearchStrings"])
984 ? $Data["KeywordSearchStrings"] : array();
985
986 # load any subgroups
987 $this->Subgroups = array();
988 if (isset($Data["Subgroups"]))
989 {
990 foreach ($Data["Subgroups"] as $SubgroupData)
991 {
992 $this->Subgroups[] = new SearchParameterSet($SubgroupData);
993 }
994 }
995 }
996
1001 private function ConvertToLegacyGroup()
1002 {
1003 $Group = array();
1004 # for each set of search strings
1005 foreach ($this->SearchStrings as $Field => $Strings)
1006 {
1007 # get text name of field
1008 $FieldName = call_user_func(self::$PrintableFieldFunction, $Field);
1009
1010 # add set to group
1011 $Group["SearchStrings"][$FieldName] = $Strings;
1012 }
1013
1014 # for each keyword search string
1015 foreach ($this->KeywordSearchStrings as $String)
1016 {
1017 # add string to keyword entry in group
1018 $Group["SearchStrings"]["XXXKeywordXXX"][] = $String;
1019 }
1020
1021 # if we had any search terms
1022 if (count($Group))
1023 {
1024 # smash single-value arrays to a scalar
1025 foreach ($Group["SearchStrings"] as &$Tgt)
1026 {
1027 if (count($Tgt) == 1)
1028 {
1029 $Tgt = current($Tgt);
1030 }
1031 }
1032
1033 # set logic for search group
1034 $Group["Logic"] = ($this->Logic == "OR")
1035 ? SearchEngine::LOGIC_OR : SearchEngine::LOGIC_AND;
1036 }
1037
1038 return $Group;
1039 }
1040
1045 private function LoadFromLegacyGroup($Group)
1046 {
1047 # set logic appropriately
1048 $this->Logic(
1049 ($Group["Logic"] == SearchEngine::LOGIC_OR) ?
1050 "OR" : "AND" );
1051
1052 # if this group had no search strings, we're done
1053 if (!isset($Group["SearchStrings"]))
1054 {
1055 return;
1056 }
1057
1058 # otherwise, load the search strings
1059 foreach ($Group["SearchStrings"] as $Field => $Params)
1060 {
1061 # skip empty groups
1062 if (count($Params)==0)
1063 {
1064 continue;
1065 }
1066
1067 $this->AddParameter( $Params,
1068 ($Field == "XXXKeywordXXX" ? NULL : $Field) );
1069
1070 }
1071 }
1072
1078 private function GetAsUrlParameters($SetPrefix = "")
1079 {
1080 # for each search string group in set
1081 $Params = array();
1082 foreach ($this->SearchStrings as $FieldId => $Values)
1083 {
1084 # get numeric version of field ID if not already numeric
1085 if (!is_numeric($FieldId))
1086 {
1087 $FieldId = call_user_func(self::$CanonicalFieldFunction, $FieldId);
1088 }
1089
1090 # for each search string in group
1091 $ParamSuffix = "";
1092 foreach ($Values as $Value)
1093 {
1094 # check for too many search strings for this field
1095 if ($ParamSuffix == "Z")
1096 {
1097 throw new Exception("Maximum search parameter complexity"
1098 ." exceeded: more than 26 search parameters for"
1099 ." field ID ".$FieldId.".");
1100 }
1101
1102 # add search string to URL
1103 $Params[self::$UrlParameterPrefix.$SetPrefix
1104 .$FieldId.$ParamSuffix] = $Value;
1105 $ParamSuffix = ($ParamSuffix == "") ? "A"
1106 : chr(ord($ParamSuffix) + 1);
1107 }
1108 }
1109
1110 # for each keyword search string
1111 $ParamSuffix = "";
1112 foreach ($this->KeywordSearchStrings as $Value)
1113 {
1114 # check for too many keyword search strings
1115 if ($ParamSuffix == "Z")
1116 {
1117 throw new Exception("Maximum search parameter complexity"
1118 ." exceeded: more than 26 keyword search parameters.");
1119 }
1120
1121 # add search string to URL
1122 $Params[self::$UrlParameterPrefix.$SetPrefix
1123 .self::URL_KEYWORD_INDICATOR.$ParamSuffix] = $Value;
1124 $ParamSuffix = ($ParamSuffix == "") ? "A"
1125 : chr(ord($ParamSuffix) + 1);
1126 }
1127
1128 # add logic if not default
1129 if ($this->Logic != self::DEFAULT_LOGIC)
1130 {
1131 $Params[self::$UrlParameterPrefix.$SetPrefix
1132 .self::URL_LOGIC_INDICATOR] = $this->Logic;
1133 }
1134
1135 # for each search parameter subgroup
1136 $SetLetter = "A";
1137 foreach ($this->Subgroups as $Subgroup)
1138 {
1139 # check for too many subgroups
1140 if ($SetLetter == "Z")
1141 {
1142 throw new Exception("Maximum search parameter complexity"
1143 ." exceeded: more than 24 search parameter subgroups.");
1144 }
1145
1146 # retrieve URL string for subgroup and add it to URL
1147 $Params = array_merge($Params, $Subgroup->GetAsUrlParameters(
1148 $SetPrefix.$SetLetter));
1149
1150 # move to next set letter
1151 $SetLetter = ($SetLetter == chr(ord(self::URL_KEYWORD_INDICATOR) - 1))
1152 ? chr(ord(self::URL_KEYWORD_INDICATOR) + 1)
1153 : chr(ord($SetLetter) + 1);
1154 }
1155
1156 # return constructed URL parameter string to caller
1157 return $Params;
1158 }
1159
1166 private function SetFromUrlParameters($UrlParameters)
1167 {
1168 # if string was passed in
1169 if (is_string($UrlParameters))
1170 {
1171 # split string into parameter array
1172 $Params = explode("&", $UrlParameters);
1173
1174 # pare down parameter array to search parameter elements
1175 # and strip off search parameter prefix
1176 $NewUrlParameters = array();
1177 foreach ($Params as $Param)
1178 {
1179 if (strpos($Param, self::$UrlParameterPrefix) === 0)
1180 {
1181 list($Index, $Value) = explode("=", $Param);
1182 $NewUrlParameters[$Index] = urldecode($Value);
1183 }
1184 }
1185 $UrlParameters = $NewUrlParameters;
1186 }
1187
1188 # for each search parameter
1189 foreach ($UrlParameters as $ParamName => $SearchString)
1190 {
1191 # strip off standard search parameter prefix
1192 $ParamName = substr($ParamName, strlen(self::$UrlParameterPrefix));
1193
1194 # split parameter into component parts
1195 $SplitResult = preg_match("/^([".self::URL_KEYWORDFREE_RANGE."]*)"
1196 ."([0-9".self::URL_KEYWORD_INDICATOR."]+)([A-Z]*)$/",
1197 $ParamName, $Matches);
1198
1199 # if split was successful
1200 if ($SplitResult === 1)
1201 {
1202 # pull components from split pieces
1203 $SetPrefix = $Matches[1];
1204 $FieldId = $Matches[2];
1205 $ParamSuffix = $Matches[3];
1206
1207 # if set prefix indicates parameter is part of our set
1208 if ($SetPrefix == "")
1209 {
1210 switch ($FieldId)
1211 {
1212 case self::URL_LOGIC_INDICATOR:
1213 # set logic
1214 $this->Logic($SearchString);
1215 break;
1216
1217 case self::URL_KEYWORD_INDICATOR:
1218 # add string to keyword searches
1219 $this->KeywordSearchStrings[] = $SearchString;
1220 break;
1221
1222 default:
1223 # add string to searches for appropriate field
1224 $this->SearchStrings[$FieldId][] = $SearchString;
1225 break;
1226 }
1227 }
1228 else
1229 {
1230 # add parameter to array for subgroup
1231 $SubgroupIndex = $SetPrefix[0];
1232 $SubgroupPrefix = (strlen($SetPrefix) > 1)
1233 ? substr($SetPrefix, 1) : "";
1234 $SubgroupParamIndex = self::$UrlParameterPrefix
1235 .$SubgroupPrefix.$FieldId.$ParamSuffix;
1236 $SubgroupParameters[$SubgroupIndex][$SubgroupParamIndex]
1237 = $SearchString;
1238 }
1239 }
1240 }
1241
1242 # if subgroups were found
1243 if (isset($SubgroupParameters))
1244 {
1245 # for each identified subgroup
1246 foreach ($SubgroupParameters as $SubgroupIndex => $Parameters)
1247 {
1248 # create subgroup and set parameters
1249 $Subgroup = new SearchParameterSet();
1250 $Subgroup->SetFromUrlParameters($Parameters);
1251
1252 # add subgroup to our set
1253 $this->Subgroups[] = $Subgroup;
1254 }
1255 }
1256 }
1257
1263 private static function NormalizeField($Field)
1264 {
1265 if (($Field !== NULL) && isset(self::$CanonicalFieldFunction))
1266 {
1267 $Field = call_user_func(self::$CanonicalFieldFunction, $Field);
1268 }
1269 return $Field;
1270 }
1271 }
SearchParameterSet\TextDescription
TextDescription($IncludeHtml=TRUE, $StartWithBreak=TRUE, $TruncateLongWordsTo=0, $Indent="")
Get text description of search parameter set.
Definition: SearchParameterSet.php:529
SearchParameterSet\Data
Data($NewValue=NULL)
Get/set search parameter set data, in the form of an opaque string.
Definition: SearchParameterSet.php:441
SearchParameterSet\TranslateLegacySearchValues
static TranslateLegacySearchValues($Field, $Values)
Translate legacy search values to modern equivalents if possible.
Definition: SearchParameterSet.php:932
SearchParameterSet\SetFromLegacyArray
SetFromLegacyArray($SearchGroups)
Set search parameters from legacy array format.
Definition: SearchParameterSet.php:778
SearchParameterSet\SetCanonicalFieldFunction
static SetCanonicalFieldFunction($Func)
Register function used to retrieve a canonical value for a field.
Definition: SearchParameterSet.php:55
SearchParameterSet
Set of parameters used to perform a search.
Definition: SearchParameterSet.php:13
SearchParameterSet\AddSet
AddSet(SearchParameterSet $Set)
Add subgroup of search parameters to set.
Definition: SearchParameterSet.php:288
SearchParameterSet\UrlParameterString
UrlParameterString($NewValue=NULL)
Get/set search parameter set, in the form of an URL parameter string.
Definition: SearchParameterSet.php:500
SearchParameterSet\UrlParameters
UrlParameters($NewValue=NULL)
Get/set search parameter set, in the form of URL parameters.
Definition: SearchParameterSet.php:475
SearchParameterSet\URL_KEYWORD_INDICATOR
const URL_KEYWORD_INDICATOR
Definition: SearchParameterSet.php:959
SearchParameterSet\URL_KEYWORDFREE_RANGE
const URL_KEYWORDFREE_RANGE
Definition: SearchParameterSet.php:958
SearchParameterSet\Logic
Logic($NewValue=NULL)
Get/set logic for set.
Definition: SearchParameterSet.php:236
SearchParameterSet\GetFields
GetFields()
Get fields used in search parameters (including subgroups).
Definition: SearchParameterSet.php:406
SearchParameterSet\SetLegacyUrlTranslationFunction
static SetLegacyUrlTranslationFunction($Func)
Register function used to converrt values from the format used in a Legacy URL string to the modern v...
Definition: SearchParameterSet.php:895
SearchParameterSet\GetSearchStringsForField
GetSearchStringsForField($Field, $IncludeSubgroups=TRUE)
Get search strings for specified field.
Definition: SearchParameterSet.php:359
SearchEngine\LOGIC_OR
const LOGIC_OR
Definition: SearchEngine.php:20
SearchParameterSet\SetPrintableFieldFunction
static SetPrintableFieldFunction($Func)
Register function used to retrieve a printable value for a field.
Definition: SearchParameterSet.php:74
SearchParameterSet\ItemTypes
ItemTypes($ItemTypes=FALSE)
Get/set allowed item types.
Definition: SearchParameterSet.php:271
SearchParameterSet\SetFromLegacyUrl
SetFromLegacyUrl($ParameterString)
Set search parameters from legacy URL string.
Definition: SearchParameterSet.php:812
SearchEngine\LOGIC_AND
const LOGIC_AND
Definition: SearchEngine.php:19
PHP
PHP
Definition: RSSClient--Test.php:12
SearchParameterSet\__clone
__clone()
Class clone handler, implemented so that clones will be deep copies rather than PHP5&#39;s default shallo...
Definition: SearchParameterSet.php:40
SearchParameterSet\AddParameter
AddParameter($SearchStrings, $Field=NULL)
Add search parameter to set.
Definition: SearchParameterSet.php:105
SearchParameterSet\ConvertLegacyUrl
static ConvertLegacyUrl($ParameterString)
Convert legacy URL to the current URL format.
Definition: SearchParameterSet.php:881
SearchParameterSet\GetAsLegacyArray
GetAsLegacyArray()
Retrieve search parameters in legacy array format.
Definition: SearchParameterSet.php:724
SearchParameterSet\GetSearchStrings
GetSearchStrings($IncludeSubgroups=FALSE)
Get search strings in set.
Definition: SearchParameterSet.php:326
StdLib\NeatlyTruncateString
static NeatlyTruncateString($String, $MaxLength, $BreakAnywhere=FALSE)
Attempt to truncate a string as neatly as possible with respect to word breaks, punctuation, and HTML tags.
Definition: StdLib.php:237
SearchParameterSet\__construct
__construct($Data=NULL)
Class constructor, used to create a new set or reload an existing set from previously-constructed dat...
Definition: SearchParameterSet.php:26
SearchParameterSet\RemoveParameter
RemoveParameter($SearchStrings, $Field=NULL)
Remove search parameter from set.
Definition: SearchParameterSet.php:139
SearchParameterSet\IsLegacyUrl
static IsLegacyUrl($ParameterString)
Determine if a URL uses legacy format.
Definition: SearchParameterSet.php:868
SearchParameterSet\GetKeywordSearchStrings
GetKeywordSearchStrings()
Get keyword search strings in set.
Definition: SearchParameterSet.php:388
SearchParameterSet\ReplaceSearchString
ReplaceSearchString($Pattern, $Replacement)
Modify all search strings with the specified regular expression.
Definition: SearchParameterSet.php:688
SearchParameterSet\DEFAULT_LOGIC
const DEFAULT_LOGIC
Definition: SearchParameterSet.php:957
SearchParameterSet\URL_LOGIC_INDICATOR
const URL_LOGIC_INDICATOR
Definition: SearchParameterSet.php:960
SearchParameterSet\GetSubgroups
GetSubgroups()
Get parameter subgroups.
Definition: SearchParameterSet.php:397
SearchParameterSet\ParameterCount
ParameterCount()
Get number of search parameters in set, including those in subgroups.
Definition: SearchParameterSet.php:305
SearchParameterSet\SetTextDescriptionFilterFunction
static SetTextDescriptionFilterFunction($Func)
Register function used to filter text descriptions of searches prior to display.
Definition: SearchParameterSet.php:914