CWIS Developer Documentation

- Home
- Main Page
- Classes
- Files

- File List
- File Members

SPTSearchEngine.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SPTSearchEngine.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2011-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9
10 class SPTSearchEngine extends SearchEngine {
11
12 function SPTSearchEngine()
13 {
14 # create a database handle
15 $DB = new Database();
16
17 # pass database handle and config values to real search engine object
18 $this->SearchEngine(
19 $DB,
20 "Resources",
21 "ResourceId",
22 "ReferenceInts",
23 "SrcResourceId",
24 "DstResourceId");
25
26 # for each field defined in schema
27 $this->Schema = new MetadataSchema();
28 $Fields = $this->Schema->GetFields();
29 foreach ($Fields as $Field)
30 {
31 # determine field type for searching
32 switch ($Field->Type())
33 {
34 case MetadataSchema::MDFTYPE_TEXT:
35 case MetadataSchema::MDFTYPE_PARAGRAPH:
36 case MetadataSchema::MDFTYPE_USER:
37 case MetadataSchema::MDFTYPE_TREE:
38 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
39 case MetadataSchema::MDFTYPE_OPTION:
40 case MetadataSchema::MDFTYPE_IMAGE:
41 case MetadataSchema::MDFTYPE_FILE:
42 case MetadataSchema::MDFTYPE_URL:
43 case MetadataSchema::MDFTYPE_REFERENCE:
44 $FieldType = self::FIELDTYPE_TEXT;
45 break;
46
47 case MetadataSchema::MDFTYPE_NUMBER:
48 case MetadataSchema::MDFTYPE_FLAG:
49 $FieldType = self::FIELDTYPE_NUMERIC;
50 break;
51
52 case MetadataSchema::MDFTYPE_DATE:
53 $FieldType = self::FIELDTYPE_DATERANGE;
54 break;
55
56 case MetadataSchema::MDFTYPE_TIMESTAMP:
57 $FieldType = self::FIELDTYPE_DATE;
58 break;
59
60 case MetadataSchema::MDFTYPE_POINT:
61 $FieldType = NULL;
62 break;
63
64 default:
65 exit("ERROR: unknown field type "
66 .$Field->Type()." in SPTSearchEngine.php");
67 break;
68 }
69
70 if ($FieldType !== NULL)
71 {
72 # add field to search engine
73 $this->AddField($Field->Name(), $Field->DBFieldName(), $FieldType,
74 $Field->SearchWeight(), $Field->IncludeInKeywordSearch());
75 }
76 }
77 }
78
79 # overloaded version of method to retrieve text from DB
80 function GetFieldContent($ItemId, $FieldName)
81 {
82 # get resource object
83 $Resource = new Resource($ItemId);
84
85 # retrieve text (including variants) from resource object and return to caller
86 return $Resource->Get($FieldName, FALSE, TRUE);
87 }
88
89 # overloaded version of method to retrieve resource/phrase match list
90 function SearchFieldForPhrases($FieldName, $Phrase)
91 {
92 # normalize and escape search phrase for use in SQL query
93 $SearchPhrase = strtolower(addslashes($Phrase));
94
95 # query DB for matching list based on field type
96 $Field = $this->Schema->GetFieldByName($FieldName);
97 switch ($Field->Type())
98 {
99 case MetadataSchema::MDFTYPE_TEXT:
100 case MetadataSchema::MDFTYPE_PARAGRAPH:
101 case MetadataSchema::MDFTYPE_FILE:
102 case MetadataSchema::MDFTYPE_URL:
103 $QueryString = "SELECT DISTINCT ResourceId FROM Resources "
104 ."WHERE POSITION('".$SearchPhrase."'"
105 ." IN LOWER(`".$Field->DBFieldName()."`)) ";
106 break;
107
108 case MetadataSchema::MDFTYPE_IMAGE:
109 $QueryString = "SELECT DISTINCT ResourceId FROM Resources "
110 ."WHERE POSITION('".$SearchPhrase."'"
111 ." IN LOWER(`".$Field->DBFieldName()."AltText`)) ";
112 break;
113
114 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
115 $NameTableSize = $this->DB->Query("SELECT COUNT(*) AS NameCount"
116 ." FROM ControlledNames", "NameCount");
117 $QueryString = "SELECT DISTINCT ResourceNameInts.ResourceId "
118 ."FROM ResourceNameInts, ControlledNames "
119 ."WHERE POSITION('".$SearchPhrase."' IN LOWER(ControlledName)) "
120 ."AND ControlledNames.ControlledNameId"
121 ." = ResourceNameInts.ControlledNameId "
122 ."AND ControlledNames.FieldId = ".$Field->Id();
123 $SecondQueryString = "SELECT DISTINCT ResourceNameInts.ResourceId "
124 ."FROM ResourceNameInts, ControlledNames, VariantNames "
125 ."WHERE POSITION('".$SearchPhrase."' IN LOWER(VariantName)) "
126 ."AND VariantNames.ControlledNameId"
127 ." = ResourceNameInts.ControlledNameId "
128 ."AND ControlledNames.ControlledNameId"
129 ." = ResourceNameInts.ControlledNameId "
130 ."AND ControlledNames.FieldId = ".$Field->Id();
131 break;
132
133 case MetadataSchema::MDFTYPE_OPTION:
134 $QueryString = "SELECT DISTINCT ResourceNameInts.ResourceId "
135 ."FROM ResourceNameInts, ControlledNames "
136 ."WHERE POSITION('".$SearchPhrase."' IN LOWER(ControlledName)) "
137 ."AND ControlledNames.ControlledNameId = ResourceNameInts.ControlledNameId "
138 ."AND ControlledNames.FieldId = ".$Field->Id();
139 break;
140
141 case MetadataSchema::MDFTYPE_TREE:
142 $QueryString = "SELECT DISTINCT ResourceClassInts.ResourceId "
143 ."FROM ResourceClassInts, Classifications "
144 ."WHERE POSITION('".$SearchPhrase."' IN LOWER(ClassificationName)) "
145 ."AND Classifications.ClassificationId = ResourceClassInts.ClassificationId "
146 ."AND Classifications.FieldId = ".$Field->Id();
147 break;
148
149 case MetadataSchema::MDFTYPE_USER:
150 $UserId = $this->DB->Query("SELECT UserId FROM APUsers "
151 ."WHERE POSITION('".$SearchPhrase."' IN LOWER(UserName)) "
152 ."OR POSITION('".$SearchPhrase."' IN LOWER(RealName))", "UserId");
153 if ($UserId != NULL)
154 {
155 $QueryString = "SELECT DISTINCT ResourceId FROM Resources "
156 ."WHERE `".$Field->DBFieldName()."` = ".$UserId;
157 }
158 break;
159
160 case MetadataSchema::MDFTYPE_NUMBER:
161 if ($SearchPhrase > 0)
162 {
163 $QueryString = "SELECT DISTINCT ResourceId FROM Resources "
164 ."WHERE `".$Field->DBFieldName()."` = ".(int)$SearchPhrase;
165 }
166 break;
167
168 case MetadataSchema::MDFTYPE_FLAG:
169 case MetadataSchema::MDFTYPE_DATE:
170 case MetadataSchema::MDFTYPE_TIMESTAMP:
171 case MetadataSchema::MDFTYPE_REFERENCE:
172 # (these types not yet handled by search engine for phrases)
173 break;
174 }
175
176 # build match list based on results returned from DB
177 if (isset($QueryString))
178 {
179 $this->DMsg(7, "Performing phrase search query (<i>".$QueryString."</i>)");
180 if ($this->DebugLevel > 9) { $StartTime = microtime(TRUE); }
181 $this->DB->Query($QueryString);
182 if ($this->DebugLevel > 9)
183 {
184 $EndTime = microtime(TRUE);
185 if (($StartTime - $EndTime) > 0.1)
186 {
187 printf("SE: Query took %.2f seconds<br>\n",
188 ($EndTime - $StartTime));
189 }
190 }
191 $MatchList = $this->DB->FetchColumn("ResourceId");
192 if (isset($SecondQueryString))
193 {
194 $this->DMsg(7, "Performing second phrase search query"
195 ." (<i>".$SecondQueryString."</i>)");
196 if ($this->DebugLevel > 9) { $StartTime = microtime(TRUE); }
197 $this->DB->Query($SecondQueryString);
198 if ($this->DebugLevel > 9)
199 {
200 $EndTime = microtime(TRUE);
201 if (($StartTime - $EndTime) > 0.1)
202 {
203 printf("SE: query took %.2f seconds<br>\n",
204 ($EndTime - $StartTime));
205 }
206 }
207 $MatchList = $MatchList + $this->DB->FetchColumn("ResourceId");
208 }
209 }
210 else
211 {
212 $MatchList = array();
213 }
214
215 # return list of matching resources to caller
216 return $MatchList;
217 }
218
219 # search field for records that meet comparison
220 function SearchFieldsForComparisonMatches($FieldNames, $Operators, $Values)
221 {
222 # use SQL keyword appropriate to current search logic for combining operations
223 $CombineWord = ($this->DefaultSearchLogic == self::LOGIC_AND) ? " AND " : " OR ";
224
225 # for each comparison
226 foreach ($FieldNames as $Index => $FieldName)
227 {
228 $Operator = $Operators[$Index];
229 $Value = $Values[$Index];
230
231 # determine query based on field type
232 $Field = $this->Schema->GetFieldByName($FieldName);
233 if ($Field != NULL)
234 {
235 switch ($Field->Type())
236 {
237 case MetadataSchema::MDFTYPE_TEXT:
238 case MetadataSchema::MDFTYPE_PARAGRAPH:
239 case MetadataSchema::MDFTYPE_NUMBER:
240 case MetadataSchema::MDFTYPE_FLAG:
241 case MetadataSchema::MDFTYPE_USER:
242 case MetadataSchema::MDFTYPE_URL:
243 if (isset($Queries["Resources"]))
244 {
245 $Queries["Resources"] .= $CombineWord;
246 }
247 else
248 {
249 $Queries["Resources"] = "SELECT DISTINCT ResourceId FROM Resources WHERE ";
250 }
251 if ($Field->Type() == MetadataSchema::MDFTYPE_USER)
252 {
253 $User = new CWUser($Value);
254 $Value = $User->Id();
255 }
256 $Queries["Resources"] .= "`".$Field->DBFieldName()."` ".$Operator." '".addslashes($Value)."' ";
257 break;
258
259 case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
260 $QueryIndex = "ResourceNameInts".$Field->Id();
261 if (!isset($Queries[$QueryIndex]["A"]))
262 {
263 $Queries[$QueryIndex]["A"] =
264 "SELECT DISTINCT ResourceId"
265 ." FROM ResourceNameInts, ControlledNames "
266 ." WHERE ControlledNames.FieldId = ".$Field->Id()
267 ." AND ( ";
268 $CloseQuery[$QueryIndex]["A"] = TRUE;
269 $ComparisonCount[$QueryIndex]["A"] = 1;
270 $ComparisonCountField[$QueryIndex]["A"] = "ControlledName";
271 }
272 else
273 {
274 $Queries[$QueryIndex]["A"] .= " OR ";
275 $ComparisonCount[$QueryIndex]["A"]++;
276 }
277 $Queries[$QueryIndex]["A"] .=
278 "((ResourceNameInts.ControlledNameId"
279 ." = ControlledNames.ControlledNameId"
280 ." AND ControlledName "
281 .$Operator." '".addslashes($Value)."'))";
282 if (!isset($Queries[$QueryIndex]["B"]))
283 {
284 $Queries[$QueryIndex]["B"] =
285 "SELECT DISTINCT ResourceId"
286 . " FROM ResourceNameInts, ControlledNames,"
287 ." VariantNames "
288 ." WHERE ControlledNames.FieldId = ".$Field->Id()
289 ." AND ( ";
290 $CloseQuery[$QueryIndex]["B"] = TRUE;
291 $ComparisonCount[$QueryIndex]["B"] = 1;
292 $ComparisonCountField[$QueryIndex]["B"] = "ControlledName";
293 }
294 else
295 {
296 $Queries[$QueryIndex]["B"] .= " OR ";
297 $ComparisonCount[$QueryIndex]["B"]++;
298 }
299 $Queries[$QueryIndex]["B"] .=
300 "((ResourceNameInts.ControlledNameId"
301 ." = ControlledNames.ControlledNameId"
302 ." AND ResourceNameInts.ControlledNameId"
303 ." = VariantNames.ControlledNameId"
304 ." AND VariantName "
305 .$Operator." '".addslashes($Value)."'))";
306 break;
307
308 case MetadataSchema::MDFTYPE_OPTION:
309 $QueryIndex = "ResourceNameInts".$Field->Id();
310 if (!isset($Queries[$QueryIndex]))
311 {
312 $Queries[$QueryIndex] =
313 "SELECT DISTINCT ResourceId FROM ResourceNameInts, ControlledNames "
314 ." WHERE ControlledNames.FieldId = ".$Field->Id()
315 ." AND ( ";
316 $CloseQuery[$QueryIndex] = TRUE;
317 $ComparisonCount[$QueryIndex] = 1;
318 $ComparisonCountField[$QueryIndex] = "ControlledName";
319 }
320 else
321 {
322 $Queries[$QueryIndex] .= " OR ";
323 $ComparisonCount[$QueryIndex]++;
324 }
325 $Queries[$QueryIndex] .= "(ResourceNameInts.ControlledNameId = ControlledNames.ControlledNameId"
326 ." AND ControlledName ".$Operator." '".addslashes($Value)."')";
327 break;
328
329 case MetadataSchema::MDFTYPE_TREE:
330 $QueryIndex = "ResourceClassInts".$Field->Id();
331 if (!isset($Queries[$QueryIndex]))
332 {
333 $Queries[$QueryIndex] = "SELECT DISTINCT ResourceId FROM ResourceClassInts, Classifications "
334 ." WHERE ResourceClassInts.ClassificationId = Classifications.ClassificationId"
335 ." AND Classifications.FieldId = ".$Field->Id()." AND ( ";
336 $CloseQuery[$QueryIndex] = TRUE;
337 $ComparisonCount[$QueryIndex] = 1;
338 $ComparisonCountField[$QueryIndex] = "ClassificationName";
339 }
340 else
341 {
342 $Queries[$QueryIndex] .= " OR ";
343 $ComparisonCount[$QueryIndex]++;
344 }
345 $Queries[$QueryIndex] .= " ClassificationName ".$Operator." '".addslashes($Value)."'";
346 break;
347
348 case MetadataSchema::MDFTYPE_TIMESTAMP:
349 # if value appears to have time component or text description
350 if (strpos($Value, ":")
351 || strstr($Value, "day")
352 || strstr($Value, "week")
353 || strstr($Value, "month")
354 || strstr($Value, "year")
355 || strstr($Value, "hour")
356 || strstr($Value, "minute"))
357 {
358 if (isset($Queries["Resources"]))
359 {
360 $Queries["Resources"] .= $CombineWord;
361 }
362 else
363 {
364 $Queries["Resources"] = "SELECT DISTINCT ResourceId"
365 ." FROM Resources WHERE ";
366 }
367
368 # flip operator if necessary
369 if (strstr($Value, "ago"))
370 {
371 $OperatorFlipMap = array(
372 "<" => ">=",
373 ">" => "<=",
374 "<=" => ">",
375 ">=" => "<",
376 );
377 $Operator = isset($OperatorFlipMap[$Operator])
378 ? $OperatorFlipMap[$Operator] : $Operator;
379 }
380
381 # use strtotime method to build condition
382 $TimestampValue = strtotime($Value);
383 if (($TimestampValue !== FALSE) && ($TimestampValue != -1))
384 {
385 if ((date("H:i:s", $TimestampValue) == "00:00:00")
386 && (strpos($Value, "00:00") === FALSE)
387 && ($Operator == "<="))
388 {
389 $NormalizedValue =
390 date("Y-m-d", $TimestampValue)." 23:59:59";
391 }
392 else
393 {
394 $NormalizedValue = date("Y-m-d H:i:s", $TimestampValue);
395 }
396 }
397 else
398 {
399 $NormalizedValue = addslashes($Value);
400 }
401 $Queries["Resources"] .=
402 " ( `".$Field->DBFieldName()."` "
403 .$Operator
404 ." '".$NormalizedValue."' ) ";
405 }
406 else
407 {
408 # use Date object method to build condition
409 $Date = new Date($Value);
410 if ($Date->Precision())
411 {
412 if (isset($Queries["Resources"]))
413 {
414 $Queries["Resources"] .= $CombineWord;
415 }
416 else
417 {
418 $Queries["Resources"] = "SELECT DISTINCT ResourceId"
419 ." FROM Resources WHERE ";
420 }
421 $Queries["Resources"] .= " ( ".$Date->SqlCondition(
422 $Field->DBFieldName(), NULL, $Operator)." ) ";
423 }
424 }
425 break;
426
427 case MetadataSchema::MDFTYPE_DATE:
428 $Date = new Date($Value);
429 if ($Date->Precision())
430 {
431 if (isset($Queries["Resources"]))
432 {
433 $Queries["Resources"] .= $CombineWord;
434 }
435 else
436 {
437 $Queries["Resources"] = "SELECT DISTINCT ResourceId"
438 ." FROM Resources WHERE ";
439 }
440 $Queries["Resources"] .= " ( ".$Date->SqlCondition(
441 $Field->DBFieldName()."Begin",
442 $Field->DBFieldName()."End", $Operator)." ) ";
443 }
444 break;
445
446 case MetadataSchema::MDFTYPE_REFERENCE:
447 $QueryIndex = "ReferenceInts".$Field->Id();
448 if (!isset($Queries[$QueryIndex]))
449 {
450 if (!isset($NameField))
451 {
452 $NameField =
453 $this->Schema->GetFieldByMappedName(
454 "Title");
455 }
456 $Queries[$QueryIndex] =
457 "SELECT DISTINCT RI.SrcResourceId AS ResourceId"
458 ." FROM ReferenceInts AS RI, Resources AS R "
459 ." WHERE RI.FieldId = ".$Field->Id()
460 ." AND (";
461 $CloseQuery[$QueryIndex] = TRUE;
462 $ComparisonCount[$QueryIndex] = 1;
463 $ComparisonCountField[$QueryIndex] =
464 "R.`".$NameField->DBFieldName()."`";
465 }
466 else
467 {
468 $Queries[$QueryIndex] .= $CombineWord;
469 $ComparisonCount[$QueryIndex]++;
470 }
471 $Queries[$QueryIndex] .= "(R.`".$NameField->DBFieldName()."` "
472 .$Operator." '".addslashes($Value)."'"
473 ." AND R.ResourceId = RI.DstResourceId)";
474 break;
475
476 case MetadataSchema::MDFTYPE_IMAGE:
477 case MetadataSchema::MDFTYPE_FILE:
478 # (these types not yet handled by search engine for comparisons)
479 break;
480 }
481 }
482 }
483
484 # if queries found
485 if (isset($Queries))
486 {
487 # for each assembled query
488 foreach ($Queries as $QueryIndex => $Query)
489 {
490 # if query has multiple parts
491 if (is_array($Query))
492 {
493 # for each part of query
494 $ResourceIds = array();
495 foreach ($Query as $PartIndex => $PartQuery)
496 {
497 # add closing paren if query was flagged to be closed
498 if (isset($CloseQuery[$QueryIndex][$PartIndex]))
499 {
500 $PartQuery .= ") ";
501 if (($this->DefaultSearchLogic == self::LOGIC_AND)
502 && ($ComparisonCount[$QueryIndex][$PartIndex] > 1))
503 {
504 $PartQuery .= "GROUP BY ResourceId"
505 ." HAVING COUNT(DISTINCT "
506 .$ComparisonCountField[$QueryIndex][$PartIndex]
507 .") = "
508 .$ComparisonCount[$QueryIndex][$PartIndex];
509 }
510 }
511
512 # perform query and retrieve IDs
513 $this->DMsg(5, "Performing comparison query <i>"
514 .$PartQuery."</i>");
515 $this->DB->Query($PartQuery);
516 $ResourceIds = $ResourceIds
517 + $this->DB->FetchColumn("ResourceId");
518 $this->DMsg(5, "Comparison query produced <i>"
519 .count($ResourceIds)."</i> results");
520 }
521 }
522 else
523 {
524 # add closing paren if query was flagged to be closed
525 if (isset($CloseQuery[$QueryIndex]))
526 {
527 $Query .= ") ";
528 if (($this->DefaultSearchLogic == self::LOGIC_AND)
529 && ($ComparisonCount[$QueryIndex] > 1))
530 {
531 $Query .= "GROUP BY ResourceId"
532 ." HAVING COUNT(DISTINCT "
533 .$ComparisonCountField[$QueryIndex]
534 .") = "
535 .$ComparisonCount[$QueryIndex];
536 }
537 }
538
539 # perform query and retrieve IDs
540 $this->DMsg(5, "Performing comparison query <i>".$Query."</i>");
541 $this->DB->Query($Query);
542 $ResourceIds = $this->DB->FetchColumn("ResourceId");
543 $this->DMsg(5, "Comparison query produced <i>"
544 .count($ResourceIds)."</i> results");
545 }
546
547 # if we already have some results
548 if (isset($Results))
549 {
550 # if search logic is set to AND
551 if ($this->DefaultSearchLogic == self::LOGIC_AND)
552 {
553 # remove anything from results that was not returned from query
554 $Results = array_intersect($Results, $ResourceIds);
555 }
556 else
557 {
558 # add values returned from query to results
559 $Results = array_unique(array_merge($Results, $ResourceIds));
560 }
561 }
562 else
563 {
564 # set results to values returned from query
565 $Results = $ResourceIds;
566 }
567 }
568 }
569 else
570 {
571 # initialize results to empty list
572 $Results = array();
573 }
574
575 # return results to caller
576 return $Results;
577 }
578
579 static function GetItemIdsSortedByField($FieldName, $SortDescending)
580 {
581 $RFactory = new ResourceFactory();
582 return $RFactory->GetResourceIdsSortedBy($FieldName, !$SortDescending);
583 }
584
585 static function QueueUpdateForItem($ItemId,
586 $TaskPriority = ApplicationFramework::PRIORITY_LOW)
587 {
588 $Item = new Resource($ItemId);
589 $TaskDescription = "Update search data for"
590 ." <a href=\"r".$ItemId."\"><i>"
591 .$Item->GetMapped("Title")."</i></a>";
592 $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
593 array(intval($ItemId)), $TaskPriority, $TaskDescription);
594 }
595
596 static function RunUpdateForItem($ItemId)
597 {
598 # check that resource still exists
599 $RFactory = new ResourceFactory();
600 if (!$RFactory->ItemExists($ItemId)) { return; }
601
602 # update search data for resource
603 $SearchEngine = new SPTSearchEngine();
604 $SearchEngine->UpdateForItem($ItemId);
605
606 # And updated the cached Controlled Name and Classification mappings
607 # which are used to suggest search facets:
608 $DB = new Database();
609
610 # Get all the classifications that are associated with this resource:
611 $DB->Query("SELECT DISTINCT ClassificationId FROM ResourceClassInts "
612 ."WHERE ResourceId=".intval($ItemId));
613 $MyClasses = array();
614 foreach ($DB->FetchRows() as $Row)
615 $MyClasses []= $Row["ClassificationId"];
616
617 # Update the class map cache for this resource:
618 $DB->Query("DELETE FROM ClassificationFacetCache WHERE ResourceId=".intval($ItemId));
619
620 if (count($MyClasses)>0)
621 $DB->Query("INSERT INTO ClassificationFacetCache (ResourceId, Classes) VALUES ".
622 "(".intval($ItemId).",'".implode(",",$MyClasses)."')");
623
624 # Get all of the names that are associated with this resource:
625 $DB->Query("SELECT DISTINCT ControlledNameId FROM ResourceNameInts "
626 ."WHERE ResourceId=".intval($ItemId));
627
628 $MyNames = array();
629 foreach ($DB->FetchRows() as $Row)
630 $MyNames []= $Row["ControlledNameId"];
631
632 # Update the name map cache for this resource:
633 $DB->Query("DELETE FROM ControlledNameFacetCache WHERE ResourceId=".intval($ItemId));
634
635 if (count($MyNames)>0)
636 $DB->Query("INSERT INTO ControlledNameFacetCache (ResourceId, Names) VALUES ".
637 "(".intval($ItemId).",'".implode(",",$MyNames)."')");
638 }
639
646 static function GetResultFacets($SearchResults)
647 {
648 # Classifications and names associated with these search results:
649 $SearchClasses = array();
650 $SearchNames = array();
651
652 # Disable DB cache for the search suggestions process,
653 # This avoids memory exhaustion.
654 $DB = new Database();
655 $DB->Caching(FALSE);
656
657 if (count($SearchResults)>0)
658 {
659 # Pull out all the Classifications that were associated with our search results:
660 $DB->Query("SELECT * FROM ClassificationFacetCache "
661 ."WHERE ResourceId IN "
662 ."(".implode(",",array_keys($SearchResults)).")");
663 while ($Row=$DB->FetchRow())
664 {
665 foreach (explode(',',$Row["Classes"]) as $ClassId)
666 {
667 $SearchClasses[$ClassId] []= $Row["ResourceId"];
668 }
669 }
670
671 # Similarly with controlled names
672 $DB->Query("SELECT * from ControlledNameFacetCache "
673 ."WHERE ResourceId in "
674 ."(".implode(",",array_keys($SearchResults)).")");
675 while ($Row=$DB->FetchRow())
676 {
677 foreach (explode(',',$Row["Names"]) as $NameId)
678 {
679 $SearchNames[$NameId] []= $Row["ResourceId"];
680 }
681 }
682 }
683
684 # Generate a map of FieldId -> Field Names for all of the generated facets:
685 $SuggestionsById = array();
686
687 # Pull relevant Classification names out of the DB
688 if ( count($SearchClasses) > 0)
689 {
690 $DB->Query("SELECT FieldId,ClassificationId,ClassificationName FROM Classifications "
691 ."WHERE ClassificationId IN (".implode(",",array_keys($SearchClasses)).")");
692 while ($Row = $DB->FetchRow())
693 $SuggestionsById[$Row["FieldId"]] []=
694 array("Id" => $Row["ClassificationId"],
695 "Name" => $Row["ClassificationName"],
696 "Count" => count( $SearchClasses[ $Row["ClassificationId"] ] ) );
697 }
698
699 if (count($SearchNames)>0)
700 {
701 # Pull relevant ControlledNames out of the DB
702 $DB->Query("SELECT FieldId,ControlledNameId,ControlledName FROM ControlledNames "
703 ."WHERE ControlledNameId IN (".implode(",",array_keys($SearchNames)).")");
704 while ($Row = $DB->FetchRow())
705 $SuggestionsById[$Row["FieldId"]] []=
706 array("Id" => $Row["ControlledNameId"],
707 "Name" => $Row["ControlledName"],
708 "Count" => count( $SearchNames[ $Row["ControlledNameId"] ] ) );
709 }
710
711 # Now, translate the suggestions that we have in terms of the
712 # FieldIds to suggestions in terms of the Field Names.
713 $SuggestionsByFieldName = array();
714
715 # If we have *any* suggestions to offer:
716 if (count($SuggestionsById)>0)
717 {
718 # We'll need G_User for permissions checks:
719 global $G_User;
720 $Schema = new MetadataSchema();
721
722 # Fill in an array that maps FieldNames to search links
723 # which would be appropriate for that field
724 foreach ($SuggestionsById as $FieldId => $FieldValues)
725 {
726 $ThisField = $Schema->GetField($FieldId);
727
728 # Bail on fields taht didn't exist (possibly as a result of stale cache data)
729 # and on fields that the current user cannot view, and on fields that are disabled
730 # for advanced searching:
731 if (is_object($ThisField) &&
732 $ThisField->Status() == MetadataSchema::MDFSTAT_OK &&
733 $ThisField->IncludeInFacetedSearch() &&
734 $ThisField->Enabled() &&
735 $G_User->HasPriv($ThisField->ViewingPrivileges() ) )
736 {
737 $SuggestionsByFieldName[ $ThisField->Name() ] = array();
738
739 foreach ($FieldValues as $Value)
740 $SuggestionsByFieldName [ $ThisField->Name() ] [$Value["Id"]] =
741 array("Name" => $Value["Name"], "Count" => $Value["Count"] );
742 }
743 }
744 }
745
746 ksort($SuggestionsByFieldName);
747
748 return $SuggestionsByFieldName;
749 }
750
751 private $Schema;
752
753 # functions for backward compatability w/ old SPT code
754 function UpdateForResource($ItemId) { $this->UpdateForItem($ItemId); }
755 }
MetadataSchema\MDFTYPE_IMAGE
const MDFTYPE_IMAGE
Definition: MetadataSchema.php:30
MetadataSchema\MDFTYPE_TIMESTAMP
const MDFTYPE_TIMESTAMP
Definition: MetadataSchema.php:24
SearchEngine\$DB
$DB
Definition: SearchEngine.php:734
SPTSearchEngine
Definition: SPTSearchEngine.php:10
SPTSearchEngine\SearchFieldForPhrases
SearchFieldForPhrases($FieldName, $Phrase)
Definition: SPTSearchEngine.php:90
MetadataSchema\MDFTYPE_FILE
const MDFTYPE_FILE
Definition: MetadataSchema.php:31
MetadataSchema
Metadata schema (in effect a Factory class for MetadataField).
Definition: MetadataSchema.php:13
ApplicationFramework\PRIORITY_LOW
const PRIORITY_LOW
Lower priority.
Definition: ApplicationFramework.php:2044
SPTSearchEngine\SPTSearchEngine
SPTSearchEngine()
Definition: SPTSearchEngine.php:12
Database
SQL database abstraction object with smart query caching.
Definition: Axis--Database.php:22
MetadataSchema\MDFTYPE_REFERENCE
const MDFTYPE_REFERENCE
Definition: MetadataSchema.php:34
SPTSearchEngine\UpdateForResource
UpdateForResource($ItemId)
Definition: SPTSearchEngine.php:754
MetadataSchema\MDFSTAT_OK
const MDFSTAT_OK
Definition: MetadataSchema.php:42
MetadataSchema\MDFTYPE_NUMBER
const MDFTYPE_NUMBER
Definition: MetadataSchema.php:22
SearchEngine\AddField
AddField($FieldName, $DBFieldName, $FieldType, $Weight, $UsedInKeywordSearch)
Definition: SearchEngine.php:54
SPTSearchEngine\GetFieldContent
GetFieldContent($ItemId, $FieldName)
Definition: SPTSearchEngine.php:80
SearchEngine\SearchEngine
SearchEngine(&$DB, $ItemTableName, $ItemIdFieldName, $ReferenceTableName, $ReferenceSourceIdFieldName, $ReferenceDestinationIdFieldName)
Definition: SearchEngine.php:26
MetadataSchema\MDFTYPE_TREE
const MDFTYPE_TREE
Definition: MetadataSchema.php:26
Date
Definition: Axis--Date.php:18
MetadataSchema\MDFTYPE_OPTION
const MDFTYPE_OPTION
Definition: MetadataSchema.php:28
MetadataSchema\MDFTYPE_FLAG
const MDFTYPE_FLAG
Definition: MetadataSchema.php:25
MetadataSchema\MDFTYPE_CONTROLLEDNAME
const MDFTYPE_CONTROLLEDNAME
Definition: MetadataSchema.php:27
PHP
PHP
Definition: OAIClient.php:39
SearchEngine\DebugLevel
DebugLevel($Setting)
Definition: SearchEngine.php:77
SPTSearchEngine\RunUpdateForItem
static RunUpdateForItem($ItemId)
Definition: SPTSearchEngine.php:596
SPTSearchEngine\GetResultFacets
static GetResultFacets($SearchResults)
Generate a list of suggested additional search terms that can be used for faceted searching...
Definition: SPTSearchEngine.php:646
MetadataSchema\MDFTYPE_PARAGRAPH
const MDFTYPE_PARAGRAPH
Definition: MetadataSchema.php:21
SPTSearchEngine\SearchFieldsForComparisonMatches
SearchFieldsForComparisonMatches($FieldNames, $Operators, $Values)
Definition: SPTSearchEngine.php:220
MetadataSchema\MDFTYPE_DATE
const MDFTYPE_DATE
Definition: MetadataSchema.php:23
SearchEngine\DMsg
DMsg($Level, $Msg)
Definition: SearchEngine.php:2001
Resource
Represents a &quot;resource&quot; in CWIS.
Definition: Resource.php:13
MetadataSchema\MDFTYPE_URL
const MDFTYPE_URL
Definition: MetadataSchema.php:32
MetadataSchema\MDFTYPE_TEXT
const MDFTYPE_TEXT
Definition: MetadataSchema.php:20
SPTSearchEngine\GetItemIdsSortedByField
static GetItemIdsSortedByField($FieldName, $SortDescending)
Definition: SPTSearchEngine.php:579
SearchEngine
Definition: SearchEngine.php:11
MetadataSchema\MDFTYPE_USER
const MDFTYPE_USER
Definition: MetadataSchema.php:29
SearchEngine\DefaultSearchLogic
DefaultSearchLogic($NewSetting=NULL)
Definition: SearchEngine.php:285
MetadataSchema\MDFTYPE_POINT
const MDFTYPE_POINT
Definition: MetadataSchema.php:33
ResourceFactory
Factory for Resource objects.
Definition: ResourceFactory.php:13
CWUser
CWIS-specific user class.
Definition: CWUser.php:13
SearchEngine\UpdateForItem
UpdateForItem($ItemId)
Definition: SearchEngine.php:357
SPTSearchEngine\QueueUpdateForItem
static QueueUpdateForItem($ItemId, $TaskPriority=ApplicationFramework::PRIORITY_LOW)
Definition: SPTSearchEngine.php:585