ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilSearchResult.php
Go to the documentation of this file.
1<?php
2
20
29{
30 private string $permission = 'visible';
31
32 private int $user_id;
33 private array $entries = array();
34 private array $results = array();
35 private array $observers = array();
36 private int $max_hits = 0;
37
39 protected int $offset = 0;
40
41 // OBJECT VARIABLES
43 protected ilDBInterface $db;
44 protected ilTree $tree;
45 protected ilObjUser $user;
47 protected LOMServices $lom_services;
48
49 // Stores info if MAX HITS is reached or not
50 public bool $limit_reached = false;
51
52 protected bool $preventOverwritingMaxhits = false;
53
54 protected ilLogger $logger;
55
56 public function __construct(int $a_user_id = 0)
57 {
58 global $DIC;
59
60 $this->logger = $DIC->logger()->src();
61 $this->ilAccess = $DIC->access();
62 $this->db = $DIC->database();
63 $this->tree = $DIC->repositoryTree();
64 $this->user = $DIC->user();
65 $this->lom_services = $DIC->learningObjectMetadata();
66
67 if ($a_user_id) {
68 $this->user_id = $a_user_id;
69 } else {
70 $this->user_id = $this->user->getId();
71 }
73 $this->initUserSearchCache();
74 }
75
79 public function setRequiredPermission(string $a_permission): void
80 {
81 $this->permission = $a_permission;
82 }
83
84 public function getRequiredPermission(): string
85 {
86 return $this->permission;
87 }
88
89 public function setUserId(int $a_user_id): void
90 {
91 $this->user_id = $a_user_id;
92 }
93 public function getUserId(): int
94 {
95 return $this->user_id;
96 }
97
98 public function getEntries(): array
99 {
100 return $this->entries;
101 }
102
103 public function isLimitReached(): bool
104 {
106 }
107
108 public function setMaxHits(int $a_max_hits): void
109 {
110 $this->max_hits = $a_max_hits;
111 }
112 public function getMaxHits(): int
113 {
114 return $this->max_hits;
115 }
116
120 public function isOffsetReached(int $a_counter): bool
121 {
122 return !($a_counter < $this->offset);
123 }
124
136 public function addEntry(
137 int $a_obj_id,
138 string $a_type,
139 array $found,
140 int $a_child_id = 0,
141 string $a_child_type = ''
142 ): void {
143 // Create new entry if it not exists
144 if (!isset($this->entries[$a_obj_id])) {
145 $this->entries[$a_obj_id]['obj_id'] = $a_obj_id;
146 $this->entries[$a_obj_id]['type'] = $a_type;
147 $this->entries[$a_obj_id]['found'] = $found;
148 $this->entries[$a_obj_id]['child'] = [];
149
150 if ($a_child_id and $a_child_id != $a_obj_id) {
151 $this->entries[$a_obj_id]['child'][$a_child_type . '__' . $a_child_id] = [
152 'id' => $a_child_id, 'type' => $a_child_type
153 ];
154 }
155 } else {
156 // replace or add child ('pg','st') id and type
157 if ($a_child_id and $a_child_id != $a_obj_id) {
158 $this->entries[$a_obj_id]['child'][$a_child_type . '__' . $a_child_id] = [
159 'id' => $a_child_id, 'type' => $a_child_type
160 ];
161 }
162 $counter = 0;
163 foreach ($found as $position) {
164 if ($position) {
165 $this->entries[$a_obj_id]['found'][$counter] = $position;
166 }
167 $counter++;
168 }
169 }
170 }
171
172 public function numEntries(): int
173 {
174 return count($this->getEntries());
175 }
176
181 public function mergeEntries(ilSearchResult $result_obj): void
182 {
183 foreach ($result_obj->getEntries() as $obj_id => $entry) {
184 $this->addEntry($entry['obj_id'], $entry['type'], $entry['found']);
185 $this->__updateEntryChilds($entry['obj_id'], $entry['child']);
186 }
187 }
188
193 public function diffEntriesFromResult(): void
194 {
195 $new_entries = $this->getEntries();
196 $this->entries = array();
197
198 // Get all checked objects
199 foreach ($this->search_cache->getCheckedItems() as $ref_id => $obj_id) {
200 if (isset($new_entries[$obj_id])) {
201 $this->addEntry(
202 $new_entries[$obj_id]['obj_id'],
203 $new_entries[$obj_id]['type'],
204 $new_entries[$obj_id]['found']
205 );
206 $this->__updateEntryChilds(
207 $new_entries[$obj_id]['obj_id'],
208 $new_entries[$obj_id]['child']
209 );
210 }
211 }
212 }
213
217 public function intersectEntries(ilSearchResult $result_obj): void
218 {
219 $new_entries = $this->getEntries();
220 $this->entries = [];
221 foreach ($result_obj->getEntries() as $entry) {
222 $obj_id = $entry['obj_id'];
223 if (isset($new_entries[$obj_id])) {
224 $this->addEntry(
225 $new_entries[$obj_id]['obj_id'],
226 $new_entries[$obj_id]['type'],
227 $new_entries[$obj_id]['found']
228 );
229
230 $this->__updateEntryChilds(
231 $new_entries[$obj_id]['obj_id'],
232 $new_entries[$obj_id]['child']
233 );
234 }
235 }
236 }
237
238 public function addResult(int $a_ref_id, int $a_obj_id, string $a_type): void
239 {
240 $this->results[$a_ref_id]['ref_id'] = $a_ref_id;
241 $this->results[$a_ref_id]['obj_id'] = $a_obj_id;
242 $this->results[$a_ref_id]['type'] = $a_type;
243 }
244
245 public function getResults(): array
246 {
247 return $this->results;
248 }
249
253 public function getResultIds(): array
254 {
255 $ids = [];
256 foreach ($this->getResults() as $id => $tmp) {
257 $ids[] = $id;
258 }
259 return $ids;
260 }
261
262 public function getResultsByObjId(): array
263 {
264 $tmp_res = [];
265 foreach ($this->getResults() as $ref_id => $res_data) {
266 $tmp_res[$res_data['obj_id']][] = $ref_id;
267 }
268 return $tmp_res;
269 }
270
275 public function getUniqueResults(): array
276 {
277 $obj_ids = [];
278 $objects = [];
279 foreach ($this->results as $result) {
280 if (in_array($result['obj_id'], $obj_ids)) {
281 continue;
282 }
283 $obj_ids[] = $result['obj_id'];
284 $objects[] = $result;
285 }
286 return $objects;
287 }
288
289 public function getResultsForPresentation(): array
290 {
291 $res = [];
292 foreach ($this->getResults() as $result) {
293 if (!is_array($result)) {
294 continue;
295 }
296
297 $res[(int) $result['ref_id']] = (int) $result['obj_id'];
298 }
299 return $res;
300 }
301
305 public function getSubitemIds(): array
306 {
307 $res = array();
308 foreach ($this->getResults() as $row) {
309 $res[$row['obj_id']] = $row['child'] ?? [];
310 }
311 return $res;
312 }
313
320 public function filter(
321 int $a_root_node,
322 bool $check_and,
323 ?ilDate $creation_filter_date_start = null,
324 ?ilDate $creation_filter_date_end = null,
325 array $copyright_identifiers = []
326 ): bool {
327 // check for copyright of all entries at once
328 if ($copyright_identifiers !== []) {
329 $entries_with_copyright = $this->findEntriesWithCopyright(...$copyright_identifiers);
330 }
331
332 // get ref_ids and check access
333 $counter = 0;
334 $offset_counter = 0;
335 foreach ($this->getEntries() as $entry) {
336 // boolean and failed continue
337 if ($check_and and in_array(0, $entry['found'])) {
338 continue;
339 }
340 // Types like role, rolt, user do not need rbac checks
341 $type = ilObject::_lookupType($entry['obj_id']);
342 if ($type == 'rolt' or $type == 'usr' or $type == 'role') {
343 if ($this->callListeners($entry['obj_id'], $entry)) {
344 $this->addResult($entry['obj_id'], $entry['obj_id'], $type);
345 if (is_array($entry['child'])) {
346 $counter += count($entry['child']);
347 }
348 // Stop if maximum of hits is reached
349 if (++$counter > $this->getMaxHits()) {
350 $this->limit_reached = true;
351 return true;
352 }
353 }
354 continue;
355 }
356
357 /*
358 * (Re-)check creation date, needed for searches on other tables than obj_data (35275)
359 * Before- and after-operators also allow matching datetimes, see ilObjectSearch::performSearch.
360 */
361 if (!is_null($creation_filter_date_start) || !is_null($creation_filter_date_end)) {
362 if (
363 !ilObject::_exists($entry['obj_id']) ||
364 ($creation_date_string = ilObject::_lookupCreationDate($entry['obj_id'])) === ''
365 ) {
366 continue;
367 }
368 $creation_date = new ilDate(
369 date('Y-m-d', strtotime($creation_date_string)),
371 );
372
373 if ($creation_filter_date_start && is_null($creation_filter_date_end)) {
374 if (!ilDate::_after($creation_date, $creation_filter_date_start)) {
375 continue;
376 }
377 } elseif ($creation_filter_date_end && is_null($creation_filter_date_start)) {
378 if (!ilDate::_before($creation_date, $creation_filter_date_end)) {
379 continue;
380 }
381 } elseif (!ilDate::_within($creation_date, $creation_filter_date_start, $creation_filter_date_end)) {
382 continue;
383 }
384 }
385
386 // filter by copyright
387 $filtered_children = $entry['child'];
388 if ($copyright_identifiers !== []) {
389 foreach ($filtered_children as $key => $child) {
390 if (in_array(
391 $entry['obj_id'] . '__' . $child['id'] . '__' . $child['type'],
392 $entries_with_copyright
393 )) {
394 continue;
395 }
396 unset($filtered_children[$key]);
397 }
398 if (
399 empty($filtered_children) &&
400 !in_array(
401 $entry['obj_id'] . '__' . $entry['obj_id'] . '__' . $entry['type'],
402 $entries_with_copyright
403 )
404 ) {
405 continue;
406 }
407
408 }
409
410 // Check referenced objects
411 foreach (ilObject::_getAllReferences((int) $entry['obj_id']) as $ref_id) {
412 // Failed check: if ref id check is failed by previous search
413 if ($this->search_cache->isFailed($ref_id)) {
414 continue;
415 }
416 // Offset check
417 if ($this->search_cache->isChecked($ref_id) and !$this->isOffsetReached($offset_counter)) {
418 ++$offset_counter;
419 continue;
420 }
421
422 if (!$this->callListeners($ref_id, $entry)) {
423 continue;
424 }
425
426
427
428 // RBAC check
429 $type = ilObject::_lookupType($ref_id, true);
430 if ($this->ilAccess->checkAccessOfUser(
431 $this->getUserId(),
432 $this->getRequiredPermission(),
433 '',
434 $ref_id,
435 $type,
436 $entry['obj_id']
437 )) {
438 if ($a_root_node == ROOT_FOLDER_ID or $this->tree->isGrandChild($a_root_node, $ref_id)) {
439 // Call listeners
440 #if($this->callListeners($ref_id,$entry))
441 if (1) {
442 $this->addResult($ref_id, $entry['obj_id'], $type);
443 $this->search_cache->appendToChecked($ref_id, $entry['obj_id']);
444 $this->__updateResultChilds($ref_id, $filtered_children);
445 ilObject::_lookupType($entry['obj_id']);
446 $counter++;
447 $offset_counter++;
448 // Stop if maximum of hits is reached
449
450 if ($counter >= $this->getMaxHits()) {
451 $this->limit_reached = true;
452 $this->search_cache->setResults($this->results);
453 return true;
454 }
455 }
456 }
457 continue;
458 }
459 $this->search_cache->appendToFailed($ref_id);
460 }
461 }
462 $this->search_cache->setResults($this->results);
463 return false;
464 }
465
470 protected function findEntriesWithCopyright(string ...$copyright_identifiers): array
471 {
472 $filters = [];
473 foreach ($this->entries as $entry) {
474 $filters[] = $this->lom_services->search()->getFilter(
475 $entry['obj_id'],
476 0,
477 $entry['type']
478 );
479 foreach ($entry['child'] as $child) {
480 $filters[] = $this->lom_services->search()->getFilter(
481 $entry['obj_id'],
482 $child['id'],
483 $child['type']
484 );
485 }
486 }
487
488 $clause = $this->lom_services->copyrightHelper()->getCopyrightSearchClause(...$copyright_identifiers);
489 $results = $this->lom_services->search()->execute($clause, null, null, ...$filters);
490
491 $ids = [];
492 foreach ($results as $result) {
493 $ids[] = $result->objID() . '__' . $result->subID() . '__' . $result->type();
494 }
495 return $ids;
496 }
497
501 public function filterResults(int $a_root_node): void
502 {
503 $tmp_results = $this->getResults();
504 $this->results = array();
505 foreach ($tmp_results as $result) {
506 if (isset($result['ref_id']) && $this->tree->isGrandChild($a_root_node, $result['ref_id']) && $this->tree->isInTree($result['ref_id'])) {
507 $this->addResult($result['ref_id'], $result['obj_id'], $result['type']);
508 $this->__updateResultChilds($result['ref_id'], $result['child'] ?? []);
509 }
510 }
511 }
512
513 public function save(int $a_type = ilUserSearchCache::DEFAULT_SEARCH): void
514 {
515 $this->search_cache->save();
516 }
517
518 public function read(int $a_type = ilUserSearchCache::DEFAULT_SEARCH): void
519 {
520 $this->results = $this->search_cache->getResults();
521 }
522
528 public function __updateEntryChilds(int $a_obj_id, array $a_childs): bool
529 {
530 if ($this->entries[$a_obj_id] and is_array($a_childs)) {
531 foreach ($a_childs as $child_info) {
532 if ($child_info) {
533 $this->entries[$a_obj_id]['child'][$child_info['type'] . '__' . $child_info['id']] = $child_info;
534 }
535 }
536 return true;
537 }
538 return false;
539 }
540
544 public function __updateResultChilds(int $a_ref_id, array $a_childs): bool
545 {
546 if ($this->results[$a_ref_id] and is_array($a_childs)) {
547 foreach ($a_childs as $child_info) {
548 $this->results[$a_ref_id]['child'][$child_info['type'] . '__' . $child_info['id']] = $child_info;
549 }
550 return true;
551 }
552 return false;
553 }
554
555 public function __initSearchSettingsObject(): void
556 {
557 $this->search_settings = new ilSearchSettings();
558 if (!$this->preventOverwritingMaxhits()) {
559 $this->setMaxHits($this->search_settings->getMaxHits());
560 }
561 }
562
563 protected function initUserSearchCache(): void
564 {
565 $this->search_cache = ilUserSearchCache::_getInstance($this->getUserId());
566 $this->offset = $this->getMaxHits() * ($this->search_cache->getResultPageNumber() - 1) ;
567 }
568
576 public function preventOverwritingMaxhits(?bool $a_flag = null)
577 {
578 if (null === $a_flag) {
579 return $this->preventOverwritingMaxhits;
580 }
581
582 $this->preventOverwritingMaxhits = $a_flag;
583
584 return $this;
585 }
586
595 public function addObserver(object $a_class, string $a_method): bool
596 {
597 $this->observers[] = array('class' => $a_class,
598 'method' => $a_method);
599 return true;
600 }
601
602
603 public function callListeners(int $a_ref_id, array $a_data): bool
604 {
605 foreach ($this->observers as $observer) {
606 $class = &$observer['class'];
607 $method = $observer['method'];
608
609 if (!$class->$method($a_ref_id, $a_data)) {
610 return false;
611 }
612 }
613 return true;
614 }
615}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
const IL_CAL_DATE
Class ilAccessHandler Checks access for ILIAS objects.
checkAccessOfUser(int $a_user_id, string $a_permission, string $a_cmd, int $a_ref_id, string $a_type="", ?int $a_obj_id=0, ?int $a_tree_id=0)
check access for an object (provide $a_type and $a_obj_id if available for better performance)
static _after(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
compare two dates and check start is after end This method does not consider tz offsets.
static _within(ilDateTime $dt, ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
Check whether an date is within a date duration given by start and end.
static _before(ilDateTime $start, ilDateTime $end, string $a_compare_field='', string $a_tz='')
compare two dates and check start is before end This method does not consider tz offsets.
Class for single dates.
Component logger with individual log levels by component id.
User class.
static _lookupType(int $id, bool $reference=false)
static _getAllReferences(int $id)
get all reference ids for object ID
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
static _lookupCreationDate(int $obj_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setUserId(int $a_user_id)
isOffsetReached(int $a_counter)
Check if offset is reached.
setRequiredPermission(string $a_permission)
Set the required permission for the rbac checks in function 'filter()'.
getUniqueResults()
Get unique results.
callListeners(int $a_ref_id, array $a_data)
addEntry(int $a_obj_id, string $a_type, array $found, int $a_child_id=0, string $a_child_type='')
add search result entry Entries are stored with 'obj_id'.
read(int $a_type=ilUserSearchCache::DEFAULT_SEARCH)
addResult(int $a_ref_id, int $a_obj_id, string $a_type)
__construct(int $a_user_id=0)
__updateEntryChilds(int $a_obj_id, array $a_childs)
LOMServices $lom_services
findEntriesWithCopyright(string ... $copyright_identifiers)
setMaxHits(int $a_max_hits)
diffEntriesFromResult()
diff entries of this instance and another result object Used for search in results
preventOverwritingMaxhits(?bool $a_flag=null)
If you call this function and pass "true" the maxhits setting will not be overwritten in __initSearch...
ilUserSearchCache $search_cache
intersectEntries(ilSearchResult $result_obj)
Build intersection of entries (all entries that are present in both result sets)
mergeEntries(ilSearchResult $result_obj)
merge entries of this instance and another result object
addObserver(object $a_class, string $a_method)
The observer is used to call functions for filtering result.
ilSearchSettings $search_settings
save(int $a_type=ilUserSearchCache::DEFAULT_SEARCH)
__updateResultChilds(int $a_ref_id, array $a_childs)
Update children for a specific result.
filterResults(int $a_root_node)
Filter search area of result set.
filter(int $a_root_node, bool $check_and, ?ilDate $creation_filter_date_start=null, ?ilDate $creation_filter_date_end=null, array $copyright_identifiers=[])
Filter search result.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
Class for storing search result.
static _getInstance(int $a_usr_id)
const ROOT_FOLDER_ID
Definition: constants.php:32
Interface ilDBInterface.
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
$results
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$counter