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