ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilUserQuery.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22use ILIAS\User\Profile\Fields\Field as ProfileField;
23use ILIAS\User\Profile\Fields\ConfigurationRepository as ProfileFieldsConfigurationRepository;
25
32{
33 public const DEFAULT_ORDER_FIELD = 'login';
34
35 private Language $lng;
36
38 private string $order_dir = 'asc';
39 private int $offset = 0;
40 private int $limit = 50;
41 private string $text_filter = '';
42 private string $activation = '';
43 private ?ilDateTime $last_login = null;
44 private bool $limited_access = false;
45 private bool $no_courses = false;
46 private bool $no_groups = false;
47 private int $crs_grp = 0;
48 private int $role = 0;
49 private ?array $user_folder = null; // Missing array type.
50 private array $additional_fields = []; // Missing array type.
51 private array $users = []; // Missing array type.
52 private string $first_letter = '';
53 private bool $has_access = false;
54 private string $authentication_method = '';
55 protected array $udf_filter = []; // Missing array type.
57 private array $default_fields = [
58 "usr_id",
59 "login",
60 "firstname",
61 "lastname",
62 "email",
63 "second_email",
64 "time_limit_until",
65 "time_limit_unlimited",
66 "time_limit_owner",
67 "last_login",
68 "active"
69 ];
70
71 private ProfileFieldsConfigurationRepository $profile_fields_repository;
72
73 public function __construct()
74 {
76 global $DIC;
77 $this->lng = $DIC['lng'];
78 $this->profile_fields_repository = LocalDIC::dic()[ProfileFieldsConfigurationRepository::class];
79 }
80
85 public function setUdfFilter(array $filter_array): void // Missing array type.
86 {
87 $field_names = array_reduce(
88 $this->profile_fields_repository->get(),
89 function (array $c, ProfileField $v): array {
90 if (!$v->isCustom()) {
91 return $c;
92 }
93 $c[] = $v->getLabel($this->lng);
94 return $c;
95 },
96 []
97 );
98
99 $valid_udfs = [];
100 foreach ($filter_array as $udf_name => $udf_value) {
101 [, $udf_id] = explode('_', $udf_name);
102 if (in_array($udf_id, $field_names)) {
103 $valid_udfs[$udf_name] = $udf_value;
104 }
105 }
106 $this->udf_filter = $valid_udfs;
107 }
108
113 public function getUdfFilter(): array // Missing array type.
114 {
115 return $this->udf_filter;
116 }
117
122 public function setOrderField(string $a_order): void
123 {
124 $this->order_field = $a_order;
125 }
126
132 public function setOrderDirection(string $a_dir): void
133 {
134 $this->order_dir = $a_dir;
135 }
136
137 public function setOffset(int $a_offset): void
138 {
139 $this->offset = $a_offset;
140 }
141
142 public function setLimit(int $a_limit): void
143 {
144 $this->limit = $a_limit;
145 }
146
150 public function setTextFilter(string $a_filter): void
151 {
152 $this->text_filter = $a_filter;
153 }
154
159 public function setActionFilter(string $a_activation): void
160 {
161 $this->activation = $a_activation;
162 }
163
167 public function setLastLogin(?ilDateTime $dt = null): void
168 {
169 $this->last_login = $dt;
170 }
171
175 public function setLimitedAccessFilter(bool $a_status): void
176 {
177 $this->limited_access = $a_status;
178 }
179
180 public function setNoCourseFilter(bool $a_no_course): void
181 {
182 $this->no_courses = $a_no_course;
183 }
184
185 public function setNoGroupFilter(bool $a_no_group): void
186 {
187 $this->no_groups = $a_no_group;
188 }
189
194 public function setCourseGroupFilter(int $a_cg_id): void
195 {
196 $this->crs_grp = $a_cg_id;
197 }
198
203 public function setRoleFilter(int $a_role_id): void
204 {
205 $this->role = $a_role_id;
206 }
207
212 public function setUserFolder(?array $a_fold_id): void // Missing array type.
213 {
214 $this->user_folder = $a_fold_id;
215 }
216
220 public function setAdditionalFields(array $a_add): void // Missing array type.
221 {
222 $this->additional_fields = $a_add;
223 }
224
228 public function setUserFilter(array $a_filter): void // Missing array type.
229 {
230 $this->users = $a_filter;
231 }
232
236 public function setFirstLetterLastname(string $a_fll): void
237 {
238 $this->first_letter = $a_fll;
239 }
240
244 public function setAccessFilter(bool $a_access): void
245 {
246 $this->has_access = $a_access;
247 }
248
253 public function setAuthenticationFilter(string $a_authentication): void
254 {
255 $this->authentication_method = $a_authentication;
256 }
257
262 public function query(): array
263 {
264 global $DIC;
265
266 $ilDB = $DIC['ilDB'];
267
268
269 $udf_fields = [];
270 $usr_ids = [];
271
272 $join = "";
273
274 if (is_array($this->additional_fields)) {
275 foreach ($this->additional_fields as $f) {
276 if (!in_array($f, $this->default_fields)) {
277 if ($f === "online_time") {
278 $this->default_fields[] = "ut_online.online_time";
279 $join = " LEFT JOIN ut_online ON (usr_data.usr_id = ut_online.usr_id) ";
280 } elseif ($f === 'dpro_agreed_on') {
281 $this->default_fields[] = 'dpro.dpro_agreed_on';
282 $join = ' LEFT JOIN (SELECT value AS dpro_agreed_on, usr_id FROM usr_pref WHERE keyword = "dpro_agree_date") AS dpro' .
283 ' ON (usr_data.usr_id = dpro.usr_id)';
284 } elseif (substr($f, 0, 4) === "udf_") {
285 $udf_fields[] = (int) substr($f, 4);
286 } else {
287 $this->default_fields[] = $f;
288 }
289 }
290 }
291 }
292
293 // if udf fields are involved we need the definitions
294 $udf_def = [];
295 // join udf table
296 foreach ($udf_fields as $id) {
297 $join .= " LEFT JOIN udf_clob ud_" . $id . " ON (ud_" . $id . ".field_id=" . $ilDB->quote($id) . " AND ud_" . $id . ".usr_id = usr_data.usr_id) ";
298 }
299
300 // count query
301 $count_query = "SELECT count(usr_data.usr_id) cnt" .
302 " FROM usr_data";
303
304 $all_multi_fields = ["interests_general", "interests_help_offered", "interests_help_looking"];
305 $multi_fields = [];
306
307 $sql_fields = [];
308 foreach ($this->default_fields as $idx => $field) {
309 if (!$field) {
310 continue;
311 }
312
313 if (in_array($field, $all_multi_fields)) {
314 $multi_fields[] = $field;
315 } elseif (strpos($field, ".") === false) {
316 $sql_fields[] = "usr_data." . $field;
317 } else {
318 $sql_fields[] = $field;
319 }
320 }
321
322 // udf fields
323 foreach ($udf_fields as $id) {
324 $sql_fields[] = "ud_" . $id . ".value udf_" . $id;
325 }
326
327 // basic query
328 $query = "SELECT " . implode(",", $sql_fields) .
329 " FROM usr_data" .
330 $join;
331
332 $count_query .= " " . $join;
333
334 // filter
335 $query .= " WHERE usr_data.usr_id <> " . $ilDB->quote(ANONYMOUS_USER_ID, "integer");
336
337 // User filter
338 $count_query .= " WHERE 1 = 1 ";
339 $count_user_filter = "usr_data.usr_id != " . $ilDB->quote(ANONYMOUS_USER_ID, "integer");
340 if ($this->users && is_array(($this->users))) {
341 $query .= ' AND ' . $ilDB->in('usr_data.usr_id', $this->users, false, 'integer');
342 $count_user_filter = $ilDB->in('usr_data.usr_id', $this->users, false, 'integer');
343 }
344
345 $count_query .= " AND " . $count_user_filter . " ";
346 $where = " AND";
347
348 if ($this->first_letter != "") {
349 $add = $where . " (" . $ilDB->upper($ilDB->substr("usr_data.lastname", 1, 1)) . " = " . $ilDB->upper($ilDB->quote($this->first_letter, "text")) . ") ";
350 $query .= $add;
351 $count_query .= $add;
352 $where = " AND";
353 }
354
355 if ($this->text_filter != "") { // email, name, login
356 $add = $where . " (" . $ilDB->like("usr_data.login", "text", "%" . $this->text_filter . "%") . " " .
357 "OR " . $ilDB->like("usr_data.firstname", "text", "%" . $this->text_filter . "%") . " " .
358 "OR " . $ilDB->like("usr_data.lastname", "text", "%" . $this->text_filter . "%") . " " .
359 "OR " . $ilDB->like("usr_data.second_email", "text", "%" . $this->text_filter . "%") . " " .
360 "OR " . $ilDB->like("usr_data.email", "text", "%" . $this->text_filter . "%") . ") ";
361 $query .= $add;
362 $count_query .= $add;
363 $where = " AND";
364 }
365
366 if ($this->activation != "") { // activation
367 if ($this->activation === "inactive") {
368 $add = $where . " usr_data.active = " . $ilDB->quote(0, "integer") . " ";
369 } else {
370 $add = $where . " usr_data.active = " . $ilDB->quote(1, "integer") . " ";
371 }
372 $query .= $add;
373 $count_query .= $add;
374 $where = " AND";
375 }
376
377 if ($this->last_login instanceof ilDateTime) { // last login
378 if (ilDateTime::_before($this->last_login, new ilDateTime(time() + (60 * 60 * 24), IL_CAL_UNIX), IL_CAL_DAY)) {
379 $add = $where . " usr_data.last_login < " .
380 $ilDB->quote($this->last_login->get(IL_CAL_DATETIME), "timestamp");
381 $query .= $add;
382 $count_query .= $add;
383 $where = " AND";
384 }
385 }
386 if ($this->limited_access) { // limited access
387 $add = $where . " usr_data.time_limit_unlimited= " . $ilDB->quote(0, "integer");
388 $query .= $add;
389 $count_query .= $add;
390 $where = " AND";
391 }
392
393 // udf filter
394 foreach ($this->getUdfFilter() as $k => $f) {
395 if ($f !== '') {
396 $udf_id = explode('_', $k)[1];
397 $add = "{$where} ud_{$udf_id}.value = {$ilDB->quote($f, 'text')}";
398 if ($udf_def[$udf_id]['field_type'] === UDF_TYPE_TEXT) {
399 $add = "{$where} {$ilDB->like("ud_{$udf_id}.value", 'text', "%{$f}%")}";
400 }
401 $query .= $add;
402 $count_query .= $add;
403 $where = ' AND';
404 }
405 }
406
407 if ($this->has_access) { //user is limited but has access
408 $unlimited = "time_limit_unlimited = " . $ilDB->quote(1, 'integer');
409 $from = "time_limit_from < " . $ilDB->quote(time(), 'integer');
410 $until = "time_limit_until > " . $ilDB->quote(time(), 'integer');
411
412 $add = $where . ' (' . $unlimited . ' OR (' . $from . ' AND ' . $until . '))';
413 $query .= $add;
414 $count_query .= $add;
415 $where = " AND";
416 }
417 if ($this->no_courses) { // no courses assigned
418 $add = $where . " usr_data.usr_id NOT IN (" .
419 "SELECT DISTINCT ud.usr_id " .
420 "FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) " .
421 "JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) " .
422 "JOIN rbac_fa ON (rbac_ua.rol_id = rbac_fa.rol_id) " .
423 "JOIN tree ON (rbac_fa.parent = tree.child) " .
424 "WHERE od.title LIKE 'il_crs_%' " .
425 "AND rbac_fa.assign = 'y' " .
426 "AND tree.tree > 0)";
427 $query .= $add;
428 $count_query .= $add;
429 $where = " AND";
430 }
431 if ($this->no_groups) { // no groups assigned
432 $add = $where . " usr_data.usr_id NOT IN (" .
433 "SELECT DISTINCT ud.usr_id " .
434 "FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) " .
435 "JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) " .
436 "JOIN rbac_fa ON (rbac_ua.rol_id = rbac_fa.rol_id) " .
437 "JOIN tree ON (rbac_fa.parent = tree.child) " .
438 "WHERE od.title LIKE 'il_grp_%' " .
439 "AND rbac_fa.assign = 'y' " .
440 "AND tree.tree > 0)";
441 $query .= $add;
442 $count_query .= $add;
443 $where = " AND";
444 }
445 if ($this->crs_grp > 0) { // members of course/group
446 $cgtype = ilObject::_lookupType($this->crs_grp, true);
447 $add = $where . " usr_data.usr_id IN (" .
448 "SELECT DISTINCT ud.usr_id " .
449 "FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) " .
450 "JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) " .
451 "WHERE od.title = " . $ilDB->quote("il_" . $cgtype . "_member_" . $this->crs_grp, "text") . ")";
452 $query .= $add;
453 $count_query .= $add;
454 $where = " AND";
455 }
456 if ($this->role > 0) { // global role
457 $add = $where . " usr_data.usr_id IN (" .
458 "SELECT DISTINCT ud.usr_id " .
459 "FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) " .
460 "WHERE rbac_ua.rol_id = " . $ilDB->quote($this->role, "integer") . ")";
461 $query .= $add;
462 $count_query .= $add;
463 $where = " AND";
464 }
465
466 if ($this->user_folder) {
467 $add = $where . " " . $ilDB->in('usr_data.time_limit_owner', $this->user_folder, false, 'integer');
468 $query .= $add;
469 $count_query .= $add;
470 $where = " AND";
471 }
472
473 if ($this->authentication_method != "") { // authentication
474 $add = $where . " usr_data.auth_mode = " . $ilDB->quote($this->authentication_method, "text") . " ";
475 $query .= $add;
476 $count_query .= $add;
477 $where = " AND";
478 }
479
480 // order by
481 switch ($this->order_field) {
482 case "access_until":
483 if ($this->order_dir === "desc") {
484 $query .= " ORDER BY usr_data.active DESC, usr_data.time_limit_unlimited DESC, usr_data.time_limit_until DESC";
485 } else {
486 $query .= " ORDER BY usr_data.active ASC, usr_data.time_limit_unlimited ASC, usr_data.time_limit_until ASC";
487 }
488 break;
489
490 case "online_time":
491 if ($this->order_dir === "desc") {
492 $query .= " ORDER BY ut_online.online_time DESC";
493 } else {
494 $query .= " ORDER BY ut_online.online_time ASC";
495 }
496 break;
497
498 default:
499 if ($this->order_dir !== "asc" && $this->order_dir !== "desc") {
500 $this->order_dir = "asc";
501 }
502 if (substr($this->order_field, 0, 4) === "udf_") {
503 // #25311 check if order field is in field list
504 if (is_array($this->getUdfFilter()) && array_key_exists($this->order_field, $this->getUdfFilter())) {
505 $query .= " ORDER BY ud_" . ((int) substr($this->order_field, 4)) . ".value " . strtoupper($this->order_dir);
506 } else {
507 $query .= ' ORDER BY ' . self::DEFAULT_ORDER_FIELD . ' ' . strtoupper($this->order_dir);
508 }
509 } else {
510 if (!in_array($this->order_field, $this->default_fields)) {
511 $this->order_field = "login";
512 }
513 $query .= " ORDER BY usr_data." . $this->order_field . " " . strtoupper($this->order_dir);
514 }
515 break;
516 }
517
518 // count query
519 $set = $ilDB->query($count_query);
520 $cnt = 0;
521 if ($rec = $ilDB->fetchAssoc($set)) {
522 $cnt = $rec["cnt"];
523 }
524
527
528 // #9866: validate offset against rowcount
529 if ($offset >= $cnt) {
530 $offset = 0;
531 }
532
533 $ilDB->setLimit($limit, $offset);
534
535 if (count($multi_fields)) {
536 $usr_ids = [];
537 }
538
539 // set query
540 $set = $ilDB->query($query);
541 $result = [];
542
543 while ($rec = $ilDB->fetchAssoc($set)) {
544 $result[] = $rec;
545 if (count($multi_fields)) {
546 $usr_ids[] = (int) $rec["usr_id"];
547 }
548 }
549
550 // add multi-field-values to user-data
551 if (count($multi_fields) && count($usr_ids)) {
552 $usr_multi = [];
553 $set = $ilDB->query("SELECT * FROM usr_profile_data" .
554 " WHERE " . $ilDB->in("usr_id", $usr_ids, "", "integer"));
555 while ($row = $ilDB->fetchAssoc($set)) {
556 $usr_multi[(int) $row["usr_id"]][$row["field_id"]][] = $row["value"];
557 }
558 foreach ($result as $idx => $item) {
559 if (isset($usr_multi[$item["usr_id"]])) {
560 $result[$idx] = array_merge($item, $usr_multi[(int) $item["usr_id"]]);
561 }
562 }
563 }
564 return ["cnt" => $cnt, "set" => $result];
565 }
566
567
572 public static function getUserListData(
573 string $a_order_field,
574 string $a_order_dir,
575 int $a_offset,
576 int $a_limit,
577 string $a_string_filter = "",
578 string $a_activation_filter = "",
579 ?ilDateTime $a_last_login_filter = null,
580 bool $a_limited_access_filter = false,
581 bool $a_no_courses_filter = false,
582 int $a_course_group_filter = 0,
583 int $a_role_filter = 0,
584 ?array $a_user_folder_filter = null,
585 ?array $a_additional_fields = null,
586 ?array $a_user_filter = null,
587 string $a_first_letter = "",
588 string $a_authentication_filter = ""
589 ): array {
590 $query = new ilUserQuery();
591 $query->setOrderField($a_order_field);
592 $query->setOrderDirection($a_order_dir);
593 $query->setOffset($a_offset);
594 $query->setLimit($a_limit);
595 $query->setTextFilter($a_string_filter);
596 $query->setActionFilter($a_activation_filter);
597 $query->setLastLogin($a_last_login_filter);
598 $query->setLimitedAccessFilter($a_limited_access_filter);
599 $query->setNoCourseFilter($a_no_courses_filter);
600 $query->setCourseGroupFilter($a_course_group_filter);
601 $query->setRoleFilter($a_role_filter);
602 $query->setUserFolder($a_user_folder_filter);
603 $query->setAdditionalFields($a_additional_fields ?? []);
604 $query->setUserFilter($a_user_filter ?? []);
605 $query->setFirstLetterLastname($a_first_letter);
606 $query->setAuthenticationFilter($a_authentication_filter);
607 return $query->query();
608 }
609}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
const IL_CAL_UNIX
const IL_CAL_DATETIME
const IL_CAL_DAY
@classDescription Date and time handling
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.
static _lookupType(int $id, bool $reference=false)
User query class.
setLimitedAccessFilter(bool $a_status)
Enable limited access filter.
setLastLogin(?ilDateTime $dt=null)
Set last login filter.
setCourseGroupFilter(int $a_cg_id)
Set course / group filter object_id of course or group.
static getUserListData(string $a_order_field, string $a_order_dir, int $a_offset, int $a_limit, string $a_string_filter="", string $a_activation_filter="", ?ilDateTime $a_last_login_filter=null, bool $a_limited_access_filter=false, bool $a_no_courses_filter=false, int $a_course_group_filter=0, int $a_role_filter=0, ?array $a_user_folder_filter=null, ?array $a_additional_fields=null, ?array $a_user_filter=null, string $a_first_letter="", string $a_authentication_filter="")
Get data for user administration list.
array $additional_fields
getUdfFilter()
Get udf filter.
setUserFolder(?array $a_fold_id)
Set user folder filter reference id of user folder or category (local user administration)
setActionFilter(string $a_activation)
Set activation filter 'active' or 'inactive' or empty.
const DEFAULT_ORDER_FIELD
setOffset(int $a_offset)
setUdfFilter(array $filter_array)
Set udf filter.
setUserFilter(array $a_filter)
Array with user ids to query against.
setAdditionalFields(array $a_add)
Set additional fields (columns in usr_data or 'online_time')
setTextFilter(string $a_filter)
Text (like) filter in login, firstname, lastname or email.
setFirstLetterLastname(string $a_fll)
set first letter lastname filter
string $authentication_method
setLimit(int $a_limit)
query()
Query usr_data.
setRoleFilter(int $a_role_id)
Set role filter obj_id of role.
setAuthenticationFilter(string $a_authentication)
Set authentication filter.
ilDateTime $last_login
ProfileFieldsConfigurationRepository $profile_fields_repository
setAccessFilter(bool $a_access)
set filter for user that are limited but has access
setNoCourseFilter(bool $a_no_course)
setOrderDirection(string $a_dir)
Set order direction 'asc' or 'desc' Default is 'asc'.
setOrderField(string $a_order)
Set order field (column in usr_data) Default order is 'login'.
setNoGroupFilter(bool $a_no_group)
const ANONYMOUS_USER_ID
Definition: constants.php:27
$c
Definition: deliver.php:25
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26