ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilUserQuery.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
23use ILIAS\User\Profile\Fields\ConfigurationRepository as ProfileFieldsConfigurationRepository;
24use ILIAS\User\Profile\DataRepository as ProfileDataRepository;
26
33{
34 public const DEFAULT_ORDER_FIELD = 'login';
35
36 private const array DEFAULT_MULTI_FIELDS = [
37 'interests_general',
38 'interests_help_offered',
39 'interests_help_looking'
40 ];
41
42 private const array DEFAULT_FIELDS = [
43 'usr_id',
44 'login',
45 'firstname',
46 'lastname',
47 'email',
48 'second_email',
49 'time_limit_until',
50 'time_limit_unlimited',
51 'time_limit_owner',
52 'last_login',
53 'active'
54 ];
55
56 private Language $lng;
58
60 private string $order_dir = 'asc';
61 private int $offset = 0;
62 private int $limit = 50;
63 private string $text_filter = '';
64 private string $activation = '';
65 private ?ilDateTime $last_login = null;
66 private bool $limited_access = false;
67 private bool $no_courses = false;
68 private bool $no_groups = false;
69 private int $crs_grp = 0;
70 private int $role = 0;
71 private array $user_folder = [];
72 private array $additional_fields = [];
73 private array $users = [];
74 private string $first_letter = '';
75 private bool $has_access = false;
76 private string $authentication_method = '';
77 protected array $udf_filter = [];
78
79 private ProfileFieldsConfigurationRepository $profile_fields_repository;
80 private ProfileDataRepository $profile_data_repository;
81
82 public function __construct()
83 {
85 global $DIC;
86 $this->lng = $DIC['lng'];
87 $this->db = $DIC['ilDB'];
88
89 $local_dic = LocalDIC::dic();
90 $this->profile_fields_repository = $local_dic[ProfileFieldsConfigurationRepository::class];
91 $this->profile_data_repository = $local_dic[ProfileDataRepository::class];
92 }
93
98 public function setUdfFilter(array $filter_array): void // Missing array type.
99 {
100 $this->udf_filter = array_reduce(
101 array_keys($filter_array),
102 function (array $c, string $v) use ($filter_array): array {
103 if ($filter_array[$v] === '') {
104 return $c;
105 }
106 $c[mb_substr($v, 4)] = $filter_array[$v];
107 return $c;
108 },
109 []
110 );
111 }
112
117 public function getUdfFilter(): array // Missing array type.
118 {
119 return $this->udf_filter;
120 }
121
126 public function setOrderField(string $a_order): void
127 {
128 $this->order_field = $a_order;
129 }
130
136 public function setOrderDirection(string $a_dir): void
137 {
138 $this->order_dir = $a_dir;
139 }
140
141 public function setOffset(int $a_offset): void
142 {
143 $this->offset = $a_offset;
144 }
145
146 public function setLimit(int $a_limit): void
147 {
148 $this->limit = $a_limit;
149 }
150
154 public function setTextFilter(string $a_filter): void
155 {
156 $this->text_filter = $a_filter;
157 }
158
163 public function setActionFilter(string $a_activation): void
164 {
165 $this->activation = $a_activation;
166 }
167
171 public function setLastLogin(?ilDateTime $dt = null): void
172 {
173 $this->last_login = $dt;
174 }
175
179 public function setLimitedAccessFilter(bool $a_status): void
180 {
181 $this->limited_access = $a_status;
182 }
183
184 public function setNoCourseFilter(bool $a_no_course): void
185 {
186 $this->no_courses = $a_no_course;
187 }
188
189 public function setNoGroupFilter(bool $a_no_group): void
190 {
191 $this->no_groups = $a_no_group;
192 }
193
198 public function setCourseGroupFilter(int $a_cg_id): void
199 {
200 $this->crs_grp = $a_cg_id;
201 }
202
207 public function setRoleFilter(int $a_role_id): void
208 {
209 $this->role = $a_role_id;
210 }
211
216 public function setUserFolder(?array $user_folder_id): void
217 {
218 $this->user_folder = $user_folder_id ?? [];
219 }
220
224 public function setAdditionalFields(array $additional_fields): void
225 {
226 $this->additional_fields = $additional_fields;
227 }
228
232 public function setUserFilter(array $a_filter): void // Missing array type.
233 {
234 $this->users = $a_filter;
235 }
236
240 public function setFirstLetterLastname(string $a_fll): void
241 {
242 $this->first_letter = $a_fll;
243 }
244
248 public function setAccessFilter(bool $a_access): void
249 {
250 $this->has_access = $a_access;
251 }
252
257 public function setAuthenticationFilter(string $a_authentication): void
258 {
259 $this->authentication_method = $a_authentication;
260 }
261
266 public function query(): array
267 {
269 $query = $this->addUdfFilterToQuery(
270 $this->addOrderToQuery(
271 array_reduce(
272 $this->additional_fields,
273 function (DataQuery $c, string $v): DataQuery {
274 if (in_array($v, self::DEFAULT_FIELDS)) {
275 return $c;
276 }
277
278 if (in_array($v, self::DEFAULT_MULTI_FIELDS)) {
279 return $c->withAdditionalMultiField($v);
280 }
281
282 if ($v === 'online_time') {
283 return $c->withAdditionalAdditionalTableSelectField('ut_online.online_time')
284 ->withAdditionalJoin('LEFT JOIN ut_online ON (usr_data.usr_id = ut_online.usr_id)');
285 }
286
287 if ($v === 'dpro_agreed_on') {
288 return $c->withAdditionalAdditionalTableSelectField('dpro.dpro_agreed_on')
289 ->withAdditionalJoin(
290 'LEFT JOIN (SELECT value AS dpro_agreed_on, usr_id' . PHP_EOL
291 . 'FROM usr_pref WHERE keyword = "dpro_agree_date") AS dpro' . PHP_EOL
292 . 'ON (usr_data.usr_id = dpro.usr_id)'
293 );
294 }
295
296 if (str_starts_with($v, 'udf_')) {
297 return $c->withAdditionalUdfField(
298 $this->profile_fields_repository->getByIdentifier(mb_substr($v, 4))
299 );
300 }
301
302 return $c->withAdditionalDefaultTableSelectField($v);
303 },
304 $this->profile_data_repository->getProfileDataQuery(self::DEFAULT_FIELDS)
305 )
306 )->withLimitedUsers($this->users)
307 );
308
309 if ($this->first_letter !== '') {
310 $query = $query->withAdditionalWhere(
311 "({$this->db->upper($this->db->substr('usr_data.lastname', 1, 1))})"
312 );
313 }
314
315 if ($this->text_filter !== '') { // email, name, login
316 $query = $query->withAdditionalWhere(
317 "({$this->db->like('usr_data.login', ilDBConstants::T_TEXT, '%' . $this->text_filter . '%')} "
318 . "OR {$this->db->like('usr_data.firstname', ilDBConstants::T_TEXT, '%' . $this->text_filter . '%')} "
319 . "OR {$this->db->like('usr_data.lastname', ilDBConstants::T_TEXT, '%' . $this->text_filter . '%')} "
320 . "OR {$this->db->like('usr_data.second_email', ilDBConstants::T_TEXT, '%' . $this->text_filter . '%')} "
321 . "OR {$this->db->like('usr_data.email', ilDBConstants::T_TEXT, '%' . $this->text_filter . '%')})"
322 );
323 }
324
325 if ($this->activation === 'inactive') {
326 $query = $query->withAdditionalWhere(
327 "usr_data.active = {$this->db->quote(0, ilDBConstants::T_INTEGER)}"
328 );
329 }
330
331 if ($this->activation === 'active') {
332 $query = $query->withAdditionalWhere(
333 "usr_data.active = {$this->db->quote(1, ilDBConstants::T_INTEGER)}"
334 );
335 }
336
337 if ($this->last_login instanceof ilDateTime) { // last login
338 if (ilDateTime::_before($this->last_login, new ilDateTime(time() + (60 * 60 * 24), IL_CAL_UNIX), IL_CAL_DAY)) {
339 $query = $query->withAdditionalWhere(
340 "usr_data.last_login < {$this->db->quote($this->last_login->get(IL_CAL_DATETIME), ilDBConstants::T_TIMESTAMP)}"
341 );
342 }
343 }
344 if ($this->limited_access) {
345 $query = $query->withAdditionalWhere(
346 "usr_data.time_limit_unlimited= {$this->db->quote(0, ilDBConstants::T_INTEGER)}"
347 );
348 }
349
350 if ($this->has_access) {
351 $query = $query->withAdditionalWhere(
352 "(time_limit_unlimited = {$this->db->quote(1, ilDBConstants::T_INTEGER)} "
353 . "OR (time_limit_from < {$this->db->quote(time(), ilDBConstants::T_INTEGER)} "
354 . "AND time_limit_until > {$this->db->quote(time(), ilDBConstants::T_INTEGER)}))"
355 );
356 }
357
358 if ($this->no_courses) {
359 $query = $query->withAdditionalWhere(
360 'usr_data.usr_id NOT IN ('
361 . 'SELECT DISTINCT ud.usr_id '
362 . 'FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) '
363 . 'JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) '
364 . 'JOIN rbac_fa ON (rbac_ua.rol_id = rbac_fa.rol_id) '
365 . 'JOIN tree ON (rbac_fa.parent = tree.child) '
366 . 'WHERE od.title LIKE "il_crs_%" '
367 . 'AND rbac_fa.assign = "y" '
368 . 'AND tree.tree > 0)'
369 );
370 }
371
372 if ($this->no_groups) {
373 $query = $query->withAdditionalWhere(
374 'usr_data.usr_id NOT IN ('
375 . 'SELECT DISTINCT ud.usr_id '
376 . 'FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) '
377 . 'JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) '
378 . 'JOIN rbac_fa ON (rbac_ua.rol_id = rbac_fa.rol_id) '
379 . 'JOIN tree ON (rbac_fa.parent = tree.child) '
380 . 'WHERE od.title LIKE "il_grp_%" '
381 . 'AND rbac_fa.assign = "y" '
382 . 'AND tree.tree > 0)'
383 );
384 }
385
386 if ($this->crs_grp > 0) {
387 $cgtype = ilObject::_lookupType($this->crs_grp, true);
388 $query = $query->withAdditionalWhere(
389 'usr_data.usr_id IN ('
390 . 'SELECT DISTINCT ud.usr_id '
391 . 'FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) '
392 . 'JOIN object_data od ON (rbac_ua.rol_id = od.obj_id) '
393 . "WHERE od.title = {$this->db->quote("il_{$cgtype}_member_{$this->crs_grp}", ilDBConstants::T_TEXT)})"
394 );
395 }
396
397 if ($this->role > 0) {
398 $query = $query->withAdditionalWhere(
399 'usr_data.usr_id IN ('
400 . 'SELECT DISTINCT ud.usr_id '
401 . 'FROM usr_data ud join rbac_ua ON (ud.usr_id = rbac_ua.usr_id) '
402 . "WHERE rbac_ua.rol_id = {$this->db->quote($this->role, ilDBConstants::T_INTEGER)})"
403 );
404 }
405
406 if ($this->user_folder !== []) {
407 $query = $query->withAdditionalWhere(
408 $this->db->in('usr_data.time_limit_owner', $this->user_folder, false, ilDBConstants::T_INTEGER)
409 );
410 }
411
412 if ($this->authentication_method !== '') {
413 $query = $query->withAdditionalWhere(
414 "usr_data.auth_mode = {$this->db->quote($this->authentication_method, ilDBConstants::T_TEXT)}"
415 );
416 }
417
418 return $this->profile_data_repository->getCountAndRecordsForQuery(
419 $query,
420 $this->offset,
421 $this->limit
422 );
423 }
424
425 private function addOrderToQuery(DataQuery $query): DataQuery
426 {
427 $direction = $this->order_dir === 'desc' ? 'DESC' : 'ASC';
428 switch ($this->order_field) {
429 case 'access_until':
430 return $query->withDefaultTableOrderFields(
431 ['active', 'time_limit_unlimited', 'time_limit_until'],
432 $direction
433 );
434
435 case 'online_time':
436 return $query->withAdditionalTableOrder("ORDER BY ut_online.online_time {$direction}");
437
438 default:
439 if (!in_array($this->order_field, array_merge(self::DEFAULT_FIELDS, $this->additional_fields))) {
440 $this->order_field = 'login';
441 }
442
443 if (in_array($this->order_field, self::DEFAULT_MULTI_FIELDS)
444 || str_starts_with($this->order_field, 'udf_')) {
445 return $query->withMultiDataTableOrder($this->order_field, $this->order_dir);
446 }
447
448 return $query->withDefaultTableOrderFields([$this->order_field], $this->order_dir);
449 }
450 }
451
452 private function addUdfFilterToQuery(DataQuery $query): DataQuery
453 {
454 if ($this->getUdfFilter() === []) {
455 return $query;
456 }
457
458 $udf_filter = $this->getUdfFilter();
459 return array_reduce(
460 array_keys(
461 array_filter($udf_filter)
462 ),
463 fn(DataQuery $c, string $v): DataQuery => $c->withAdditionalMultiDataWhere(
464 $v,
465 $udf_filter[$v]
466 ),
468 );
469 }
470
471
476 public static function getUserListData(
477 string $a_order_field,
478 string $a_order_dir,
479 int $a_offset,
480 int $a_limit,
481 string $a_string_filter = "",
482 string $a_activation_filter = "",
483 ?ilDateTime $a_last_login_filter = null,
484 bool $a_limited_access_filter = false,
485 bool $a_no_courses_filter = false,
486 int $a_course_group_filter = 0,
487 int $a_role_filter = 0,
488 ?array $a_user_folder_filter = null,
489 ?array $a_additional_fields = null,
490 ?array $a_user_filter = null,
491 string $a_first_letter = "",
492 string $a_authentication_filter = ""
493 ): array {
494 $query = new ilUserQuery();
495 $query->setOrderField($a_order_field);
496 $query->setOrderDirection($a_order_dir);
497 $query->setOffset($a_offset);
498 $query->setLimit($a_limit);
499 $query->setTextFilter($a_string_filter);
500 $query->setActionFilter($a_activation_filter);
501 $query->setLastLogin($a_last_login_filter);
502 $query->setLimitedAccessFilter($a_limited_access_filter);
503 $query->setNoCourseFilter($a_no_courses_filter);
504 $query->setCourseGroupFilter($a_course_group_filter);
505 $query->setRoleFilter($a_role_filter);
506 $query->setUserFolder($a_user_folder_filter);
507 $query->setAdditionalFields($a_additional_fields ?? []);
508 $query->setUserFilter($a_user_filter ?? []);
509 $query->setFirstLetterLastname($a_first_letter);
510 $query->setAuthenticationFilter($a_authentication_filter);
511 return $query->query();
512 }
513}
withMultiDataTableOrder(string $order_field, string $direction)
Definition: DataQuery.php:116
withDefaultTableOrderFields(array $order_fields, string $direction)
Definition: DataQuery.php:123
withAdditionalTableOrder(string $order)
Definition: DataQuery.php:109
const IL_CAL_UNIX
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.
const array DEFAULT_MULTI_FIELDS
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.
setActionFilter(string $a_activation)
Set activation filter 'active' or 'inactive' or empty.
const DEFAULT_ORDER_FIELD
ilDBInterface $db
setOffset(int $a_offset)
const array DEFAULT_FIELDS
setUdfFilter(array $filter_array)
Set udf filter.
addOrderToQuery(DataQuery $query)
setUserFilter(array $a_filter)
Array with user ids to query against.
setTextFilter(string $a_filter)
Text (like) filter in login, firstname, lastname or email.
addUdfFilterToQuery(DataQuery $query)
setFirstLetterLastname(string $a_fll)
set first letter lastname filter
string $authentication_method
setUserFolder(?array $user_folder_id)
Set user folder filter reference id of user folder or category (local user administration)
setLimit(int $a_limit)
ProfileDataRepository $profile_data_repository
setAdditionalFields(array $additional_fields)
Set additional fields (columns in usr_data or 'online_time')
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)
$c
Definition: deliver.php:25
Interface ilDBInterface.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26