ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilSearchGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
23 
34 {
35  private array $details;
36  public int $root_node;
37  public string $combination;
38  public string $string;
39  public int $type;
40 
41  protected ilTabsGUI $tabs_gui;
42  protected ilHelpGUI $help_gui;
45 
46  public function __construct()
47  {
48  global $DIC;
50  $this->tabs_gui = $DIC->tabs();
51  $this->help_gui = $DIC->help();
52  $this->lng->loadLanguageModule("search");
53 
54  $this->ui_factory = $DIC->ui()->factory();
55  $this->ui_renderer = $DIC->ui()->renderer();
56 
57  $this->initFilter(self::SEARCH_FORM_STANDARD);
58 
59 
60  $requested_search = (array) ($this->http->request()->getParsedBody()['search'] ?? []);
61 
62  if ($this->http->wrapper()->post()->has('cmd')) {
63  $requested_cmd = (array) $this->http->wrapper()->post()->retrieve('cmd', $this->getStringArrayTransformation());
64  } elseif ($this->http->wrapper()->query()->has('cmd')) {
65  $requested_cmd = (array) $this->http->wrapper()->query()->retrieve(
66  'cmd',
67  $this->refinery->kindlyTo()->string()
68  );
69  $requested_cmd = [$requested_cmd[0] => "Search"];
70  } else {
71  $requested_cmd = [];
72  }
73  $new_search = (bool) ($requested_cmd["performSearch"] ?? false);
74  $new_filter = (bool) ($requested_cmd["performSearchFilter"] ?? false);
75  $new_search_or_filter = $new_search || $new_filter;
76 
77  $requested_filter_type = (array) ($this->search_filter_data["search_type"] ?? []);
78  $requested_filter_type = array_flip($requested_filter_type);
79  $requested_filter_type = array_fill_keys(array_keys($requested_filter_type), "1");
80  $enabled_types = ilSearchSettings::getInstance()->getEnabledLuceneItemFilterDefinitions();
81  foreach ($enabled_types as $type => $pval) {
82  if (isset($requested_filter_type[$type])) {
83  $requested_search["details"][$type] = $requested_filter_type[$type];
84  }
85  }
86 
87  // Search term input field and filter are handled separately, see README (Filtering behaviour)
88  $post_term = $this->http->wrapper()->post()->retrieve(
89  'term',
90  $this->refinery->byTrying([
91  $this->refinery->kindlyTo()->string(),
92  $this->refinery->always(null)
93  ])
94  );
95  $filter_type_active = (is_null($this->search_filter_data["search_type"] ?? null))
96  ? self::SEARCH_FAST
97  : self::SEARCH_DETAILS;
98  $filter_scope = $this->search_filter_data["search_scope"] ?? ROOT_FOLDER_ID;
99 
100  if ($new_filter) {
101  ilSession::set('search_root', $filter_scope);
102  }
103 
104  $requested_search["string"] = $post_term;
105  $requested_search["type"] = $filter_type_active;
106 
107  $this->root_node = (int) (ilSession::get('search_root') ?? ROOT_FOLDER_ID);
108 
109  $session_search = ilSession::get('search') ?? [];
110  $this->setType((int) ($requested_search['type'] ?? ($session_search['type'] ?? self::SEARCH_FAST)));
111 
112  $this->setCombination(
114  self::SEARCH_AND :
115  self::SEARCH_OR
116  );
117  $this->setString((string) ($requested_search['string'] ?? ($session_search['string'] ?? '')));
118  $this->setDetails(
119  $new_search_or_filter ?
120  ($requested_search['details'] ?? []) :
121  ($session_search['details'] ?? [])
122  );
123 
124  if ($new_search_or_filter) {
125  $this->getSearchCache()->setQuery(ilUtil::stripSlashes(
126  $requested_search['string'] ?? ($session_search['string'] ?? '')
127  ));
128  $this->getSearchCache()->setCreationFilter($this->loadCreationFilter());
129  $this->getSearchCache()->save();
130  }
131  }
132 
133  public function executeCommand(): void
134  {
135  $next_class = $this->ctrl->getNextClass($this);
136  $cmd = $this->ctrl->getCmd();
137 
138  switch ($next_class) {
139  case 'ilobjectcopygui':
140  $this->prepareOutput();
141  $this->ctrl->setReturn($this, '');
142  $cp = new ilObjectCopyGUI($this);
143  $this->ctrl->forwardCommand($cp);
144  break;
145 
146  default:
147  if (!$cmd) {
148  $cmd = "showSavedResults";
149  }
150  $this->prepareOutput();
151  $this->handleCommand($cmd);
152  break;
153  }
154  }
155 
159  public function setType(int $a_type): void
160  {
161  $session_search = ilSession::get('search');
162  $session_search['type'] = $this->type = $a_type;
163  ilSession::set('search', $session_search);
164  }
165 
166  public function getType(): int
167  {
168  return $this->type ?? self::SEARCH_FAST;
169  }
170 
174  public function setCombination(string $a_combination): void
175  {
176  $session_search = ilSession::get('search') ?? [];
177  $session_search['combination'] = $this->combination = $a_combination;
178  ilSession::set('search', $session_search);
179  }
180  public function getCombination(): string
181  {
182  return $this->combination ?: self::SEARCH_OR;
183  }
184 
185  public function setString(string $a_str): void
186  {
187  $session_search = ilSession::get('search') ?? [];
188  $session_search['string'] = $this->string = $a_str;
189  ilSession::set('search', $session_search);
190  }
191 
192  public function getString(): string
193  {
194  return $this->string;
195  }
196 
200  public function setDetails(array $a_details): void
201  {
202  $session_search = ilSession::get('search') ?? [];
203  $session_search['details'] = $this->details = $a_details;
204  ilSession::set('search', $session_search);
205  }
206 
207  public function getDetails(): array
208  {
209  return $this->details ?? [];
210  }
211 
212  public function getRootNode(): int
213  {
214  return $this->root_node ?: ROOT_FOLDER_ID;
215  }
216 
217  public function setRootNode(int $a_node_id): void
218  {
219  ilSession::set('search_root', $this->root_node = $a_node_id);
220  }
221 
222  public function remoteSearch(): void
223  {
224  $root_id = 0;
225  if ($this->http->wrapper()->post()->has('root_id')) {
226  $root_id = $this->http->wrapper()->post()->retrieve(
227  'root_id',
228  $this->refinery->kindlyTo()->int()
229  );
230  }
231  $queryString = '';
232  if ($this->http->wrapper()->post()->has('queryString')) {
233  $queryString = $this->http->wrapper()->post()->retrieve(
234  'queryString',
235  $this->refinery->kindlyTo()->string()
236  );
237  }
238  $this->setString($queryString);
239  $this->setRootNode($root_id);
240  $this->performSearch();
241  }
242 
246  public function autoComplete(): void
247  {
248  $query = '';
249  if ($this->http->wrapper()->post()->has('term')) {
250  $query = $this->http->wrapper()->post()->retrieve(
251  'term',
252  $this->refinery->kindlyTo()->string()
253  );
254  } elseif ($this->http->wrapper()->query()->has('term')) {
255  $query = $this->http->wrapper()->query()->retrieve(
256  'term',
257  $this->refinery->kindlyTo()->string()
258  );
259  }
260  $search_type = 0;
261  if ($this->http->wrapper()->post()->has('search_type')) {
262  $search_type = $this->http->wrapper()->post()->retrieve(
263  'search_type',
264  $this->refinery->kindlyTo()->int()
265  );
266  } elseif ($this->http->wrapper()->query()->has('search_type')) {
267  $search_type = $this->http->wrapper()->query()->retrieve(
268  'search_type',
269  $this->refinery->kindlyTo()->int()
270  );
271  }
272  if ((int) $search_type === -1) {
273  $a_fields = array('login','firstname','lastname','email');
274  $result_field = 'login';
275 
276  // Starting user autocomplete search
277  $auto = new ilUserAutoComplete();
278 
279 
280  $auto->setMoreLinkAvailable(true);
281  $auto->setSearchFields($a_fields);
282  $auto->setResultField($result_field);
283  $auto->enableFieldSearchableCheck(true);
284  $auto->setUserLimitations(true);
285 
286  $res = $auto->getList($query);
287  $res_obj = json_decode($res);
288  if (is_array($res_obj->items)) {
289  echo json_encode($res_obj->items);
290  exit;
291  }
292  } else {
293  $list = ilSearchAutoComplete::getList($query);
294  echo $list;
295  exit;
296  }
297  }
298 
299  public function showSearch(): void
300  {
301  $this->tpl->addBlockFile('ADM_CONTENT', 'adm_content', 'tpl.search.html', 'components/ILIAS/Search');
302  $this->renderSearch($this->getString(), $this->getRootNode());
303  }
304 
305  public function showSavedResults(): void
306  {
307  // Read old result sets
308 
309  $result_obj = new ilSearchResult($this->user->getId());
310  $result_obj->read();
311  $result_obj->filterResults($this->getRootNode());
312 
313  $this->showSearch();
314 
315  // Show them
316  if (count($result_obj->getResults())) {
317  $this->addPager($result_obj, 'max_page');
318 
320  $presentation->setResults($result_obj->getResultsForPresentation());
321  $presentation->setSubitemIds($result_obj->getSubitemIds());
322  $presentation->setPreviousNext($this->prev_link, $this->next_link);
323  #$presentation->setSearcher($searcher);
324 
325  if ($presentation->render()) {
326  $this->tpl->setVariable('SEARCH_RESULTS', $presentation->getHTML());
327  }
328  }
329  }
330 
331  public function performSearchFilter(): void
332  {
333  $this->performSearch();
334  }
335 
336  public function performSearch(): void
337  {
338  $page_number = $this->initPageNumberFromQuery();
339  if (!$page_number and $this->search_mode != 'in_results') {
340  ilSession::clear('max_page');
341  $this->search_cache->deleteCachedEntries();
342  }
343  $this->search_cache->setResultPageNumber($page_number);
344  if ($this->getType() == ilSearchBaseGUI::SEARCH_DETAILS and !$this->getDetails()) {
345  $this->tpl->setOnScreenMessage('info', $this->lng->txt('search_choose_object_type'));
346  $this->showSearch();
347  return;
348  }
349 
350  // Step 1: parse query string
351  if (!is_object($query_parser = $this->__parseQueryString())) {
352  $this->tpl->setOnScreenMessage('info', $query_parser);
353  $this->showSearch();
354 
355  return;
356  }
357  // Step 2: perform object search. Get an ObjectSearch object via factory. Depends on fulltext or like search type.
358  $result = $this->__searchObjects($query_parser);
359 
360  // Step 3: perform meta keyword search. Get an MetaDataSearch object.
361  $result_meta = $this->__searchMeta($query_parser, 'keyword');
362  $result->mergeEntries($result_meta);
363 
364  $result_meta = $this->__searchMeta($query_parser, 'contribute');
365  $result->mergeEntries($result_meta);
366 
367  $result_meta = $this->__searchMeta($query_parser, 'title');
368  $result->mergeEntries($result_meta);
369 
370  $result_meta = $this->__searchMeta($query_parser, 'description');
371  $result->mergeEntries($result_meta);
372 
373  // Perform details search in object specific tables
374  if ($this->getType() == self::SEARCH_DETAILS) {
375  $result = $this->__performDetailsSearch($query_parser, $result);
376  }
377  // Step 5: Search in results
378  if ($this->search_mode == 'in_results') {
379  $old_result_obj = new ilSearchResult($this->user->getId());
380  $old_result_obj->read();
381 
382  $result->diffEntriesFromResult();
383  }
384 
385 
386  // Step 4: merge and validate results
387  $result->filter(
388  $this->getRootNode(),
392  );
393  $result->save();
394  $this->showSearch();
395 
396  if (!count($result->getResults())) {
397  $this->tpl->setOnScreenMessage('info', $this->lng->txt('search_no_match'));
398  }
399 
400  if ($result->isLimitReached()) {
401  #$message = sprintf($this->lng->txt('search_limit_reached'),$this->settings->getMaxHits());
402  #ilUtil::sendInfo($message);
403  }
404 
405  // Step 6: show results
406  $this->addPager($result, 'max_page');
407 
409  $presentation->setResults($result->getResultsForPresentation());
410  $presentation->setSubitemIds($result->getSubitemIds());
411  $presentation->setPreviousNext($this->prev_link, $this->next_link);
412 
413  if ($presentation->render()) {
414  $this->tpl->setVariable('SEARCH_RESULTS', $presentation->getHTML());
415  }
416  }
417 
418  public function prepareOutput(): void
419  {
420  parent::prepareOutput();
421 
422  $this->help_gui->setScreenIdComponent("src");
423 
424  $this->tabs_gui->addTab(
425  "search",
426  $this->lng->txt("search"),
427  $this->ctrl->getLinkTarget($this)
428  );
429 
430  $this->tabs_gui->activateTab("search");
431  }
432 
433  protected function __performDetailsSearch(ilQueryParser $query_parser, ilSearchResult $result): ilSearchResult
434  {
435  foreach ($this->getDetails() as $type => $enabled) {
436  if (!$enabled) {
437  continue;
438  }
439 
440  switch ($type) {
441  case 'crs':
442  $crs_search = ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
443  $crs_search->setFilter(array('crs'));
444  $result->mergeEntries($crs_search->performSearch());
445  break;
446 
447  case 'grp':
448  $grp_search = ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
449  $grp_search->setFilter(array('grp'));
450  $result->mergeEntries($grp_search->performSearch());
451  break;
452 
453  case 'lms':
454  $content_search = ilObjectSearchFactory::_getLMContentSearchInstance($query_parser);
455  $content_search->setFilter($this->__getFilter());
456  $result->mergeEntries($content_search->performSearch());
457  break;
458 
459  case 'frm':
460  $forum_search = ilObjectSearchFactory::_getForumSearchInstance($query_parser);
461  $forum_search->setFilter($this->__getFilter());
462  $result->mergeEntries($forum_search->performSearch());
463  break;
464 
465  case 'glo':
466  // Glossary term definition pages
467  $gdf_search = ilObjectSearchFactory::_getLMContentSearchInstance($query_parser);
468  $gdf_search->setFilter(array('term'));
469  $result->mergeEntries($gdf_search->performSearch());
470  // Glossary terms
471  $gdf_term_search = ilObjectSearchFactory::_getGlossaryDefinitionSearchInstance($query_parser);
472  $result->mergeEntries($gdf_term_search->performSearch());
473  break;
474 
475  case 'exc':
476  $exc_search = ilObjectSearchFactory::_getExerciseSearchInstance($query_parser);
477  $exc_search->setFilter($this->__getFilter());
478  $result->mergeEntries($exc_search->performSearch());
479  break;
480 
481  case 'mcst':
482  $mcst_search = ilObjectSearchFactory::_getMediacastSearchInstance($query_parser);
483  $result->mergeEntries($mcst_search->performSearch());
484  break;
485 
486  case 'tst':
487  $tst_search = ilObjectSearchFactory::_getTestSearchInstance($query_parser);
488  $tst_search->setFilter($this->__getFilter());
489  $result->mergeEntries($tst_search->performSearch());
490  break;
491 
492  case 'mep':
493  $mep_search = ilObjectSearchFactory::_getMediaPoolSearchInstance($query_parser);
494  $mep_search->setFilter($this->__getFilter());
495  $result->mergeEntries($mep_search->performSearch());
496 
497  // Mob keyword search
498  $mob_search = ilObjectSearchFactory::_getMediaPoolSearchInstance($query_parser);
499  $mob_search->setFilter($this->__getFilter());
500  $result->mergeEntries($mob_search->performKeywordSearch());
501 
502  break;
503 
504  case 'wiki':
505  $wiki_search = ilObjectSearchFactory::_getWikiContentSearchInstance($query_parser);
506  $wiki_search->setFilter($this->__getFilter());
507  $result->mergeEntries($wiki_search->performSearch());
508 
509  /*$result_meta =& $this->__searchMeta($query_parser,'title');
510  $result->mergeEntries($result_meta);
511  $result_meta =& $this->__searchMeta($query_parser,'description');
512  $result->mergeEntries($result_meta);*/
513  break;
514  }
515  }
516  return $result;
517  }
518 
522  public function __parseQueryString(): ilQueryParser|string
523  {
524  $query_parser = new ilQueryParser(ilUtil::stripSlashes($this->getString()));
525  $query_parser->setCombination($this->getCombination());
526  $query_parser->parse();
527 
528  if (!$query_parser->validate()) {
529  return $query_parser->getMessage();
530  }
531  return $query_parser;
532  }
533 
537  public function __searchObjects(ilQueryParser $query_parser): ilSearchResult
538  {
539  $obj_search = ilObjectSearchFactory::_getObjectSearchInstance($query_parser);
540  if ($this->getType() == self::SEARCH_DETAILS) {
541  $obj_search->setFilter($this->__getFilter());
542  }
543  $this->parseCreationFilter($obj_search);
544  return $obj_search->performSearch();
545  }
546 
547  public function parseCreationFilter(ilObjectSearch $search): bool
548  {
549  $date_start = $this->parseStartDateFromCreationFilter();
550  $date_end = $this->parseEndDateFromCreationFilter();
551 
552  if (is_null($date_start) && is_null($date_end)) {
553  return true;
554  }
555 
556  $search->setCreationDateFilterStartDate($date_start);
557  $search->setCreationDateFilterEndDate($date_end);
558  return true;
559  }
560 
562  {
563  $options = $this->getSearchCache()->getCreationFilter();
564  if (!($options['date_start'] ?? false)) {
565  return null;
566  }
567  return new ilDate($options['date_start'] ?? "", IL_CAL_DATE);
568  }
569 
570  protected function parseEndDateFromCreationFilter(): ?ilDate
571  {
572  $options = $this->getSearchCache()->getCreationFilter();
573  if (!($options['date_end'] ?? false)) {
574  return null;
575  }
576  return new ilDate($options['date_end'] ?? "", IL_CAL_DATE);
577  }
578 
582  public function __searchMeta(ilQueryParser $query_parser, string $a_type): ilSearchResult
583  {
584  $meta_search = ilObjectSearchFactory::_getMetaDataSearchInstance($query_parser);
585  if ($this->getType() == self::SEARCH_DETAILS) {
586  $meta_search->setFilter($this->__getFilter());
587  }
588  switch ($a_type) {
589  case 'keyword':
590  $meta_search->setMode('keyword');
591  break;
592 
593  case 'contribute':
594  $meta_search->setMode('contribute');
595  break;
596 
597  case 'title':
598  $meta_search->setMode('title');
599  break;
600 
601  case 'description':
602  $meta_search->setMode('description');
603  break;
604  }
605  return $meta_search->performSearch();
606  }
607 
612  public function __getFilter(): array
613  {
614  if ($this->getType() != self::SEARCH_DETAILS) {
615  return [];
616  }
617 
618  $filter = [];
619  foreach ($this->getDetails() as $key => $detail_type) {
620  if (!$detail_type) {
621  continue;
622  }
623 
624  switch ($key) {
625  case 'lms':
626  $filter[] = 'lm';
627  $filter[] = 'dbk';
628  $filter[] = 'pg';
629  $filter[] = 'st';
630  $filter[] = 'sahs';
631  $filter[] = 'htlm';
632  break;
633 
634  case 'frm':
635  $filter[] = 'frm';
636  break;
637 
638  case 'glo':
639  $filter[] = 'glo';
640  break;
641 
642  case 'exc':
643  $filter[] = 'exc';
644  break;
645 
646  case 'mcst':
647  $filter[] = 'mcst';
648  break;
649 
650  case 'tst':
651  $filter[] = 'tst';
652  $filter[] = 'svy';
653  $filter[] = 'qpl';
654  $filter[] = 'spl';
655  break;
656 
657  case 'mep':
658  $filter[] = 'mep';
659  $filter[] = 'mob';
660  break;
661 
662  case 'fil':
663  $filter[] = 'file';
664  break;
665 
666  case 'wiki':
667  $filter[] = 'wpg';
668  break;
669 
670  default:
671  $filter[] = $key;
672  }
673  }
674  return $filter;
675  }
676 }
UIFactory $ui_factory
static get(string $a_var)
setString(string $a_str)
$res
Definition: ltiservices.php:66
setCreationDateFilterStartDate(?ilDate $day)
read(int $a_type=ilUserSearchCache::DEFAULT_SEARCH)
__searchMeta(ilQueryParser $query_parser, string $a_type)
Search in object meta data (keyword)
static _getLMContentSearchInstance(ilQueryParser $query_parser)
static _getMediaPoolSearchInstance(ilQueryParser $query_parser)
setCombination(string $a_combination)
Set/get combination of search (&#39;and&#39; or &#39;or&#39;)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__searchObjects(ilQueryParser $query_parser)
Search in obect title,desctiption.
static getList(string $a_str)
GUI class for the workflow of copying objects.
GUI class for &#39;simple&#39; search.
const ROOT_FOLDER_ID
Definition: constants.php:32
static _getMediacastSearchInstance(ilQueryParser $query_parser)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
static _getWikiContentSearchInstance(ilQueryParser $query_parser)
Help GUI class.
__performDetailsSearch(ilQueryParser $query_parser, ilSearchResult $result)
handleCommand(string $a_cmd)
setRootNode(int $a_node_id)
parseStartDateFromCreationFilter()
setType(int $a_type)
Set/get type of search (detail or &#39;fast&#39; search)
static _getExerciseSearchInstance(ilQueryParser $query_parser)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
ilHelpGUI $help_gui
static _getGlossaryDefinitionSearchInstance(ilQueryParser $query_parser)
ilTabsGUI $tabs_gui
static http()
Fetches the global http state from ILIAS.
__parseQueryString()
parse query string, using query parser instance
setCreationDateFilterEndDate(?ilDate $day)
Presentation of search results using object list gui.
static _getForumSearchInstance(ilQueryParser $query_parser)
static _getObjectSearchInstance(ilQueryParser $query_parser)
global $DIC
Definition: shib_login.php:26
parseCreationFilter(ilObjectSearch $search)
exit
renderSearch(string $term, int $root_node=0)
const IL_CAL_DATE
static _getTestSearchInstance(ilQueryParser $query_parser)
UIRenderer $ui_renderer
mergeEntries(ilSearchResult $result_obj)
merge entries of this instance and another result object
addPager($result, string $a_session_key)
__construct(Container $dic, ilPlugin $plugin)
__getFilter()
Get object type for filter (If detail search is enabled)
static _getMetaDataSearchInstance(ilQueryParser $query_parser)
static clear(string $a_var)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static set(string $a_var, $a_val)
Set a value.
setDetails(array $a_details)
Set/get details (object types for details search)
autoComplete()
Data resource for autoComplete.