ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilUserAutoComplete.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
8{
9 const MAX_ENTRIES = 1000;
10
11
16
21
26
31
35 private $logger = null;
36
40 private $searchable_check = false;
41
45 private $user_access_check = true;
46
50 private $possible_fields = array();
51
56
60 private $search_type;
61
66
70 private $user;
71
72
73 private $limit = 0;
74
75 private $user_limitations = true;
76
81
85 private $more_link_available = false;
86
90 public function __construct()
91 {
92 global $DIC;
93
94 $this->result_field = 'login';
95
96 $this->setSearchType(self::SEARCH_TYPE_LIKE);
97 $this->setPrivacyMode(self::PRIVACY_MODE_IGNORE_USER_SETTING);
98
99 $this->logger = $DIC->logger()->user();
100 }
101
105 public function respectMinimumSearchCharacterCount($a_status)
106 {
107 $this->respect_min_search_character_count = $a_status;
108 }
109
114 {
116 }
117
118
119 public function setLimit($a_limit)
120 {
121 $this->limit = $a_limit;
122 }
123
124 public function getLimit()
125 {
126 return $this->limit;
127 }
128
133 {
134 $this->search_type = $search_type;
135 }
136
140 public function getSearchType()
141 {
142 return $this->search_type;
143 }
144
149 {
150 $this->privacy_mode = $privacy_mode;
151 }
152
156 public function getPrivacyMode()
157 {
158 return $this->privacy_mode;
159 }
160
164 public function setUser($user)
165 {
166 $this->user = $user;
167 }
168
172 public function getUser()
173 {
174 return $this->user;
175 }
176
181 public function enableFieldSearchableCheck($a_status)
182 {
183 $this->searchable_check = $a_status;
184 }
185
191 {
193 }
194
200 public function enableUserAccessCheck($a_status)
201 {
202 $this->user_access_check = $a_status;
203 }
204
209 public function isUserAccessCheckEnabled()
210 {
212 }
213
218 public function setSearchFields($a_fields)
219 {
220 $this->possible_fields = $a_fields;
221 }
222
227 public function getSearchFields()
228 {
230 }
231
236 protected function getFields()
237 {
239 {
240 return $this->getSearchFields();
241 }
242 $available_fields = array();
243 foreach($this->getSearchFields() as $field)
244 {
245 include_once 'Services/Search/classes/class.ilUserSearchOptions.php';
247 {
248 $available_fields[] = $field;
249 }
250 }
251 return $available_fields;
252 }
253
258 public function setResultField($a_field)
259 {
260 $this->result_field = $a_field;
261 }
262
268 public function getList($a_str)
269 {
273 global $ilDB;
274 $parsed_query = $this->parseQueryString($a_str);
275
276
277 include_once './Services/Search/classes/class.ilQueryParser.php';
278 if(ilStr::strLen($parsed_query['query']) < ilQueryParser::MIN_WORD_LENGTH)
279 {
280 $result_json['items'] = [];
281 $result_json['hasMoreResults'] = false;
282 $this->logger->debug('Autocomplete search rejected: minimum characters count.');
283 return json_encode($result_json);
284 }
285
286
287 $select_part = $this->getSelectPart();
288 $where_part = $this->getWherePart($parsed_query);
289 $order_by_part = $this->getOrderByPart();
290 $query = implode(" ", array(
291 'SELECT ' . $select_part,
292 'FROM ' . $this->getFromPart(),
293 $where_part ? 'WHERE ' . $where_part : '',
294 $order_by_part ? 'ORDER BY ' . $order_by_part : ''
295 ));
296
297 $this->logger->debug('Query: ' . $query);
298
299 $res = $ilDB->query($query);
300
301 // add email only if it is "searchable"
302 $add_email = true;
303 include_once 'Services/Search/classes/class.ilUserSearchOptions.php';
305 {
306 $add_email = false;
307 }
308
309 include_once './Services/Search/classes/class.ilSearchSettings.php';
310 $max = $this->getLimit() ? $this->getLimit() : ilSearchSettings::getInstance()->getAutoCompleteLength();
311 $cnt = 0;
312 $more_results = FALSE;
313 $result = array();
314 while(($rec = $ilDB->fetchAssoc($res)) && $cnt < ($max + 1))
315 {
316 if($cnt >= $max && $this->isMoreLinkAvailable())
317 {
318 $more_results = TRUE;
319 break;
320 }
321
322 if (self::PRIVACY_MODE_RESPECT_USER_SETTING != $this->getPrivacyMode() || in_array($rec['profile_value'], ['y','g']))
323 {
324 $label = $rec['lastname'] . ', ' . $rec['firstname'] . ' [' . $rec['login'] . ']';
325 }
326 else
327 {
328 $label = '[' . $rec['login'] . ']';
329 }
330
331 if($add_email && $rec['email'] && (self::PRIVACY_MODE_RESPECT_USER_SETTING != $this->getPrivacyMode() || 'y' == $rec['email_value']))
332 {
333 $label .= ', ' . $rec['email'];
334 }
335
336 $result[$cnt]['value'] = (string)$rec[$this->result_field];
337 $result[$cnt]['label'] = $label;
338 $result[$cnt]['id'] = $rec['usr_id'];
339 $cnt++;
340 }
341
342 include_once 'Services/JSON/classes/class.ilJsonUtil.php';
343
344 $result_json['items'] = $result;
345 $result_json['hasMoreResults'] = $more_results;
346
347 $this->logger->dump($result_json);
348
349 return ilJsonUtil::encode($result_json);
350 }
351
355 protected function getSelectPart()
356 {
357 $fields = array(
358 'ud.usr_id',
359 'ud.login',
360 'ud.firstname',
361 'ud.lastname',
362 'ud.email'
363 );
364
365 if(self::PRIVACY_MODE_RESPECT_USER_SETTING == $this->getPrivacyMode())
366 {
367 $fields[] = 'profpref.value profile_value';
368 $fields[] = 'pubemail.value email_value';
369 }
370
371 return implode(', ', $fields);
372 }
373
377 protected function getFromPart()
378 {
382 global $ilDB;
383
384 $joins = array();
385
386 if(self::PRIVACY_MODE_RESPECT_USER_SETTING == $this->getPrivacyMode())
387 {
388 $joins[] = 'LEFT JOIN usr_pref profpref
389 ON profpref.usr_id = ud.usr_id
390 AND profpref.keyword = ' . $ilDB->quote('public_profile', 'text');
391
392 $joins[] = 'LEFT JOIN usr_pref pubemail
393 ON pubemail.usr_id = ud.usr_id
394 AND pubemail.keyword = ' . $ilDB->quote('public_email', 'text');
395 }
396
397 if($joins)
398 {
399 return 'usr_data ud ' . implode(' ', $joins);
400 }
401 else
402 {
403 return 'usr_data ud';
404 }
405 }
406
411 protected function getWherePart(array $search_query)
412 {
417 global $ilDB, $ilSetting;
418
419 $outer_conditions = array();
420
421 // In 'anonymous' context with respected user privacy, only users with globally published profiles should be found.
422 if(self::PRIVACY_MODE_RESPECT_USER_SETTING == $this->getPrivacyMode() &&
423 $this->getUser() instanceof ilObjUser &&
424 $this->getUser()->isAnonymous()
425 )
426 {
427 if(!$ilSetting->get('enable_global_profiles', 0))
428 {
429 // If 'Enable User Content Publishing' is not set in the administration, no user should be found for 'anonymous' context.
430 return '1 = 2';
431 }
432 else
433 {
434 // Otherwise respect the profile activation setting of every user (as a global (outer) condition in the where clause).
435 $outer_conditions[] = 'profpref.value = ' . $ilDB->quote('g', 'text');
436 }
437 }
438
439 $outer_conditions[] = 'ud.usr_id != ' . $ilDB->quote(ANONYMOUS_USER_ID, 'integer');
440
441 $field_conditions = array();
442 foreach($this->getFields() as $field)
443 {
444 $field_condition = $this->getQueryConditionByFieldAndValue($field, $search_query);
445
446 if('email' == $field && self::PRIVACY_MODE_RESPECT_USER_SETTING == $this->getPrivacyMode())
447 {
448 // If privacy should be respected, the profile setting of every user concerning the email address has to be
449 // respected (in every user context, no matter if the user is 'logged in' or 'anonymous').
450 $email_query = array();
451 $email_query[] = $field_condition;
452 $email_query[] = 'pubemail.value = ' . $ilDB->quote('y', 'text');
453 $field_conditions[] = '(' . implode(' AND ', $email_query) . ')';
454 }
455 else
456 {
457 $field_conditions[] = $field_condition;
458 }
459 }
460
461 // If the current user context ist 'logged in' and privacy should be respected, all fields >>>except the login<<<
462 // should only be searchable if the users' profile is published (y oder g)
463 // In 'anonymous' context we do not need this additional conditions,
464 // because we checked the privacy setting in the condition above: profile = 'g'
465 if(self::PRIVACY_MODE_RESPECT_USER_SETTING == $this->getPrivacyMode() &&
466 $this->getUser() instanceof ilObjUser && !$this->getUser()->isAnonymous() &&
467 $field_conditions
468 )
469 {
470 $fields = '(' . implode(' OR ', $field_conditions) . ')';
471
472 $field_conditions = [
473 '(' . implode(' AND ', array(
474 $fields,
475 $ilDB->in('profpref.value', array('y', 'g'), false, 'text')
476 )) . ')'
477 ];
478 }
479
480 // The login field must be searchable regardless (for 'logged in' users) of any privacy settings.
481 // We handled the general condition for 'anonymous' context above: profile = 'g'
482 $field_conditions[] = $this->getQueryConditionByFieldAndValue('login', $search_query);
483
484 include_once 'Services/User/classes/class.ilUserAccountSettings.php';
485 if(ilUserAccountSettings::getInstance()->isUserAccessRestricted())
486 {
487 include_once './Services/User/classes/class.ilUserFilter.php';
488 $outer_conditions[] = $ilDB->in('time_limit_owner', ilUserFilter::getInstance()->getFolderIds(), false, 'integer');
489 }
490
491 if($field_conditions)
492 {
493 $outer_conditions[] = '(' . implode(' OR ', $field_conditions) . ')';
494 }
495
496 include_once './Services/Search/classes/class.ilSearchSettings.php';
497 $settings = ilSearchSettings::getInstance();
498
499 if(!$settings->isInactiveUserVisible() && $this->getUserLimitations())
500 {
501 $outer_conditions[] = "ud.active = ". $ilDB->quote(1, 'integer');
502 }
503
504 if(!$settings->isLimitedUserVisible() && $this->getUserLimitations())
505 {
506 $unlimited = "ud.time_limit_unlimited = ". $ilDB->quote(1, 'integer');
507 $from = "ud.time_limit_from < ". $ilDB->quote(time(), 'integer');
508 $until = "ud.time_limit_until > ". $ilDB->quote(time(), 'integer');
509
510 $outer_conditions[] = '(' .$unlimited.' OR ('.$from.' AND ' .$until.'))';
511 }
512
513 return implode(' AND ', $outer_conditions);
514 }
515
519 protected function getOrderByPart()
520 {
521 return 'login ASC';
522 }
523
529 protected function getQueryConditionByFieldAndValue($field, $query)
530 {
534 global $ilDB;
535
536 $query_strings = array($query['query']);
537
538 if(array_key_exists($field, $query))
539 {
540 $query_strings = array($query[$field]);
541 }
542 elseif(array_key_exists('parts', $query))
543 {
544 $query_strings = $query['parts'];
545 }
546
547 $query_condition = '( ';
548 $num = 0;
549 foreach($query_strings as $query_string)
550 {
551 if($num++ > 0)
552 {
553 $query_condition .= ' OR ';
554 }
555 if(self::SEARCH_TYPE_LIKE == $this->getSearchType())
556 {
557 $query_condition .= $ilDB->like($field, 'text', $query_string . '%');
558 }
559 else
560 {
561 $query_condition .= $ilDB->like($field, 'text', $query_string);
562 }
563 }
564 $query_condition .= ')';
565 return $query_condition;
566 }
567
573 public function setUserLimitations($a_limitations)
574 {
575 $this->user_limitations = (bool) $a_limitations;
576 }
577
582 public function getUserLimitations()
583 {
585 }
586
590 public function isMoreLinkAvailable()
591 {
593 }
594
601 {
602 $this->more_link_available = $more_link_available;
603 }
604
610 public function parseQueryString($a_query)
611 {
612 $query = array();
613
614 if(!stristr($a_query, '\\'))
615 {
616 $a_query = str_replace('%', '\%', $a_query);
617 $a_query = str_replace('_', '\_', $a_query);
618 }
619
620 $query['query'] = trim($a_query);
621
622 // "," means fixed search for lastname, firstname
623 if(strpos($a_query, ','))
624 {
625 $comma_separated = (array) explode(',', $a_query);
626
627 if(count($comma_separated) == 2)
628 {
629 if(trim($comma_separated[0]))
630 {
631 $query['lastname'] = trim($comma_separated[0]);
632 }
633 if(trim($comma_separated[1]))
634 {
635 $query['firstname'] = trim($comma_separated[1]);
636 }
637 }
638 }
639 else
640 {
641 $whitespace_separated = (array) explode(' ', $a_query);
642 foreach($whitespace_separated as $part)
643 {
644 if(trim($part))
645 {
646 $query['parts'][] = trim($part);
647 }
648 }
649 }
650
651 $this->logger->dump($query, ilLogLevel::DEBUG);
652
653 return $query;
654 }
655
656
657}
$result
user()
Definition: user.php:4
An exception for terminatinating execution or to throw for unit testing.
static encode($mixed, $suppress_native=false)
const MIN_WORD_LENGTH
Minimum of characters required for search.
static strLen($a_string)
Definition: class.ilStr.php:91
static getInstance()
Singelton get instance.
Auto completion class for user lists.
getFields()
Get searchable fields.
parseQueryString($a_query)
Parse query string.
setUserLimitations($a_limitations)
allow user limitations like inactive and access limitations
__construct()
Default constructor.
getUserLimitations()
allow user limitations like inactive and access limitations
isUserAccessCheckEnabled()
Check if user access check is enabled.
isFieldSearchableCheckEnabled()
Searchable check enabled.
setResultField($a_field)
Set result field.
getSearchFields()
get possible search fields
enableFieldSearchableCheck($a_status)
Enable the check whether the field is searchable in Administration -> Settings -> Standard Fields.
setSearchFields($a_fields)
Set searchable fields.
enableUserAccessCheck($a_status)
Enable user access check.
respectMinimumSearchCharacterCount($a_status)
setMoreLinkAvailable($more_link_available)
IMPORTANT: remember to read request parameter 'fetchall' to use this function.
static getInstance()
Singelton get instance.
global $ilSetting
Definition: privfeed.php:17
global $ilDB
global $DIC