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 }
463 else
464 {
465 $Queries[$QueryIndex] .= $CombineWord;
466 }
467 $Queries[$QueryIndex] .= "(R.`".$NameField->DBFieldName()."` "
468 .$Operator." '".addslashes($Value)."'"
469 ." AND R.ResourceId = RI.DstResourceId)";
470 break;
471
472 case MetadataSchema::MDFTYPE_IMAGE:
473 case MetadataSchema::MDFTYPE_FILE:
474 # (these types not yet handled by search engine for comparisons)
475 break;
476 }
477 }
478 }
479
480 # if queries found
481 if (isset($Queries))
482 {
483 # for each assembled query
484 foreach ($Queries as $QueryIndex => $Query)
485 {
486 # if query has multiple parts
487 if (is_array($Query))
488 {
489 # for each part of query
490 $ResourceIds = array();
491 foreach ($Query as $PartIndex => $PartQuery)
492 {
493 # add closing paren if query was flagged to be closed
494 if (isset($CloseQuery[$QueryIndex][$PartIndex]))
495 {
496 $PartQuery .= " ) ";
497 if ($this->DefaultSearchLogic == self::LOGIC_AND)
498 {
499 $PartQuery .= "GROUP BY ResourceId HAVING"
500 ." COUNT(DISTINCT "
501 .$ComparisonCountField[$QueryIndex][$PartIndex]
502 .") = "
503 .$ComparisonCount[$QueryIndex][$PartIndex];
504 }
505 }
506
507 # perform query and retrieve IDs
508 $this->DMsg(5, "Performing comparison query (<i>"
509 .$PartQuery."</i>)");
510 $this->DB->Query($PartQuery);
511 $ResourceIds = $ResourceIds
512 + $this->DB->FetchColumn("ResourceId");
513 $this->DMsg(5, "Comparison query produced <i>"
514 .count($ResourceIds)."</i> results");
515 }
516 }
517 else
518 {
519 # add closing paren if query was flagged to be closed
520 if (isset($CloseQuery[$QueryIndex]))
521 {
522 $Query .= " ) ";
523 if ($this->DefaultSearchLogic == self::LOGIC_AND)
524 {
525 $Query .= "GROUP BY ResourceId HAVING"
526 ." COUNT(DISTINCT "
527 .$ComparisonCountField[$QueryIndex]
528 .") = "
529 .$ComparisonCount[$QueryIndex];
530 }
531 }
532
533 # perform query and retrieve IDs
534 $this->DMsg(5, "Performing comparison query (<i>".$Query."</i>)");
535 $this->DB->Query($Query);
536 $ResourceIds = $this->DB->FetchColumn("ResourceId");
537 $this->DMsg(5, "Comparison query produced <i>"
538 .count($ResourceIds)."</i> results");
539 }
540
541 # if we already have some results
542 if (isset($Results))
543 {
544 # if search logic is set to AND
545 if ($this->DefaultSearchLogic == self::LOGIC_AND)
546 {
547 # remove anything from results that was not returned from query
548 $Results = array_intersect($Results, $ResourceIds);
549 }
550 else
551 {
552 # add values returned from query to results
553 $Results = array_unique(array_merge($Results, $ResourceIds));
554 }
555 }
556 else
557 {
558 # set results to values returned from query
559 $Results = $ResourceIds;
560 }
561 }
562 }
563 else
564 {
565 # initialize results to empty list
566 $Results = array();
567 }
568
569 # return results to caller
570 return $Results;
571 }
572
573 static function GetItemIdsSortedByField($FieldName, $SortDescending)
574 {
575 $RFactory = new ResourceFactory();
576 return $RFactory->GetResourceIdsSortedBy($FieldName, !$SortDescending);
577 }
578
579 static function QueueUpdateForItem($ItemId,
580 $TaskPriority = ApplicationFramework::PRIORITY_LOW)
581 {
582 $Item = new Resource($ItemId);
583 $TaskDescription = "Update search data for"
584 ." <a href=\"r".$ItemId."\"><i>"
585 .$Item->GetMapped("Title")."</i></a>";
586 $GLOBALS["AF"]->QueueUniqueTask(array(__CLASS__, "RunUpdateForItem"),
587 array(intval($ItemId)), $TaskPriority, $TaskDescription);
588 }
589
590 static function RunUpdateForItem($ItemId)
591 {
592 # check that resource still exists
593 $RFactory = new ResourceFactory();
594 if (!$RFactory->ItemExists($ItemId)) { return; }
595
596 # update search data for resource
597 $SearchEngine = new SPTSearchEngine();
598 $SearchEngine->UpdateForItem($ItemId);
599
600 # And updated the cached Controlled Name and Classification mappings
601 # which are used to suggest search facets:
602 $DB = new Database();
603
604 # Get all the classifications that are associated with this resource:
605 $DB->Query("SELECT DISTINCT ClassificationId FROM ResourceClassInts "
606 ."WHERE ResourceId=".intval($ItemId));
607 $MyClasses = array();
608 foreach ($DB->FetchRows() as $Row)
609 $MyClasses []= $Row["ClassificationId"];
610
611 # Update the class map cache for this resource:
612 $DB->Query("DELETE FROM ClassificationFacetCache WHERE ResourceId=".intval($ItemId));
613
614 if (count($MyClasses)>0)
615 $DB->Query("INSERT INTO ClassificationFacetCache (ResourceId, Classes) VALUES ".
616 "(".intval($ItemId).",'".implode(",",$MyClasses)."')");
617
618 # Get all of the names that are associated with this resource:
619 $DB->Query("SELECT DISTINCT ControlledNameId FROM ResourceNameInts "
620 ."WHERE ResourceId=".intval($ItemId));
621
622 $MyNames = array();
623 foreach ($DB->FetchRows() as $Row)
624 $MyNames []= $Row["ControlledNameId"];
625
626 # Update the name map cache for this resource:
627 $DB->Query("DELETE FROM ControlledNameFacetCache WHERE ResourceId=".intval($ItemId));
628
629 if (count($MyNames)>0)
630 $DB->Query("INSERT INTO ControlledNameFacetCache (ResourceId, Names) VALUES ".
631 "(".intval($ItemId).",'".implode(",",$MyNames)."')");
632 }
633
640 static function GetResultFacets($SearchResults)
641 {
642 # Classifications and names associated with these search results:
643 $SearchClasses = array();
644 $SearchNames = array();
645
646 # Disable DB cache for the search suggestions process,
647 # This avoids memory exhaustion.
648 $DB = new Database();
649 $DB->Caching(FALSE);
650
651 if (count($SearchResults)>0)
652 {
653 # Pull out all the Classifications that were associated with our search results:
654 $DB->Query("SELECT * FROM ClassificationFacetCache "
655 ."WHERE ResourceId IN "
656 ."(".implode(",",array_keys($SearchResults)).")");
657 while ($Row=$DB->FetchRow())
658 {
659 foreach (explode(',',$Row["Classes"]) as $ClassId)
660 {
661 $SearchClasses[$ClassId] []= $Row["ResourceId"];
662 }
663 }
664
665 # Similarly with controlled names
666 $DB->Query("SELECT * from ControlledNameFacetCache "
667 ."WHERE ResourceId in "
668 ."(".implode(",",array_keys($SearchResults)).")");
669 while ($Row=$DB->FetchRow())
670 {
671 foreach (explode(',',$Row["Names"]) as $NameId)
672 {
673 $SearchNames[$NameId] []= $Row["ResourceId"];
674 }
675 }
676 }
677
678 # Generate a map of FieldId -> Field Names for all of the generated facets:
679 $SuggestionsById = array();
680
681 # Pull relevant Classification names out of the DB
682 if ( count($SearchClasses) > 0)
683 {
684 $DB->Query("SELECT FieldId,ClassificationId,ClassificationName FROM Classifications "
685 ."WHERE ClassificationId IN (".implode(",",array_keys($SearchClasses)).")");
686 while ($Row = $DB->FetchRow())
687 $SuggestionsById[$Row["FieldId"]] []=
688 array("Id" => $Row["ClassificationId"],
689 "Name" => $Row["ClassificationName"],
690 "Count" => count( $SearchClasses[ $Row["ClassificationId"] ] ) );
691 }
692
693 if (count($SearchNames)>0)
694 {
695 # Pull relevant ControlledNames out of the DB
696 $DB->Query("SELECT FieldId,ControlledNameId,ControlledName FROM ControlledNames "
697 ."WHERE ControlledNameId IN (".implode(",",array_keys($SearchNames)).")");
698 while ($Row = $DB->FetchRow())
699 $SuggestionsById[$Row["FieldId"]] []=
700 array("Id" => $Row["ControlledNameId"],
701 "Name" => $Row["ControlledName"],
702 "Count" => count( $SearchNames[ $Row["ControlledNameId"] ] ) );
703 }
704
705 # Now, translate the suggestions that we have in terms of the
706 # FieldIds to suggestions in terms of the Field Names.
707 $SuggestionsByFieldName = array();
708
709 # If we have *any* suggestions to offer:
710 if (count($SuggestionsById)>0)
711 {
712 # We'll need G_User for permissions checks:
713 global $G_User;
714 $Schema = new MetadataSchema();
715
716 # Fill in an array that maps FieldNames to search links
717 # which would be appropriate for that field
718 foreach ($SuggestionsById as $FieldId => $FieldValues)
719 {
720 $ThisField = $Schema->GetField($FieldId);
721
722 # Bail on fields taht didn't exist (possibly as a result of stale cache data)
723 # and on fields that the current user cannot view, and on fields that are disabled
724 # for advanced searching:
725 if (is_object($ThisField) &&
726 $ThisField->Status() == MetadataSchema::MDFSTAT_OK &&
727 $ThisField->IncludeInFacetedSearch() &&
728 $ThisField->Enabled() &&
729 ($ThisField->ViewingPrivilege() == FALSE ||
730 $G_User->HasPriv($ThisField->ViewingPrivilege()) ) )
731 {
732 $SuggestionsByFieldName[ $ThisField->Name() ] = array();
733
734 foreach ($FieldValues as $Value)
735 $SuggestionsByFieldName [ $ThisField->Name() ] [$Value["Id"]] =
736 array("Name" => $Value["Name"], "Count" => $Value["Count"] );
737 }
738 }
739 }
740
741 ksort($SuggestionsByFieldName);
742
743 return $SuggestionsByFieldName;
744 }
745
746 private $Schema;
747
748 # functions for backward compatability w/ old SPT code
749 function UpdateForResource($ItemId) { $this->UpdateForItem($ItemId); }
750 }
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:1979
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:749
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:590
SPTSearchEngine\GetResultFacets
static GetResultFacets($SearchResults)
Generate a list of suggested additional search terms that can be used for faceted searching...
Definition: SPTSearchEngine.php:640
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:573
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:579