Update core
[platal.git] / classes / userfilter.php
CommitLineData
a087cc8d
FB
1<?php
2/***************************************************************************
d4c08d89 3 * Copyright (C) 2003-2010 Polytechnique.org *
a087cc8d
FB
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
d865c296
FB
22
23/******************
24 * CONDITIONS
25 ******************/
26
8363588b 27// {{{ interface UserFilterCondition
2d83cac9
RB
28/** This interface describe objects which filter users based
29 * on various parameters.
30 * The parameters of the filter must be given to the constructor.
31 * The buildCondition function is called by UserFilter when
32 * actually building the query. That function must call
33 * $uf->addWheteverFilter so that the UserFilter makes
34 * adequate joins. It must return the 'WHERE' condition to use
35 * with the filter.
36 */
dcc63ed5 37interface UserFilterCondition extends PlFilterCondition
a087cc8d 38{
a087cc8d 39}
8363588b 40// }}}
a087cc8d 41
77902bed 42// {{{ class UFC_HasProfile
53eae167
RB
43/** Filters users who have a profile
44 */
77902bed 45class UFC_HasProfile implements UserFilterCondition
eb1449b8 46{
dcc63ed5 47 public function buildCondition(PlFilter &$uf)
eb1449b8 48 {
aaf70eb8 49 $uf->requireProfiles();
93b0da52 50 return '$PID IS NOT NULL';
eb1449b8
FB
51 }
52}
8363588b 53// }}}
eb1449b8 54
55aa88ed 55// {{{ class UFC_AccountType
2192fcfc 56/** Filters users who have one of the given account types
55aa88ed
FB
57 */
58class UFC_AccountType implements UserFilterCondition
59{
60 private $types;
61
62 public function __construct()
63 {
64 $this->types = pl_flatten(func_get_args());
65 }
66
67 public function buildCondition(PlFilter &$uf)
68 {
69 $uf->requireAccounts();
70 return XDB::format('a.type IN {?}', $this->types);
71 }
72}
1eabd2a4
FB
73// }}}
74
75// {{{ class UFC_AccountPerm
2192fcfc 76/** Filters users who have one of the given permissions
1eabd2a4
FB
77 */
78class UFC_AccountPerm implements UserFilterCondition
79{
80 private $perms;
81
82 public function __construct()
83 {
84 $this->perms = pl_flatten(func_get_args());
85 }
86
87 public function buildCondition(PlFilter &$uf)
88 {
89 $uf->requirePerms();
90 $conds = array();
91 foreach ($this->perms as $perm) {
92 $conds[] = XDB::format('FIND_IN_SET({?}, IF(a.user_perms IS NULL, at.perms,
93 CONCAT(at.perms, \',\', a.user_perms)))',
94 $perm);
95 }
96 if (empty($conds)) {
97 return self::COND_TRUE;
98 } else {
99 return implode(' OR ', $conds);
100 }
101 }
102}
2192fcfc 103// }}}
55aa88ed 104
ddba9d4f
RB
105// {{{ class UFC_Hruid
106/** Filters users based on their hruid
107 * @param $val Either an hruid, or a list of those
108 */
109class UFC_Hruid implements UserFilterCondition
110{
111 private $hruids;
112
61d1fd8b 113 public function __construct()
ddba9d4f 114 {
61d1fd8b 115 $this->hruids = pl_flatten(func_get_args());
ddba9d4f
RB
116 }
117
118 public function buildCondition(PlFilter &$uf)
119 {
7752f73f 120 $uf->requireAccounts();
bde68f05 121 return XDB::format('a.hruid IN {?}', $this->hruids);
ddba9d4f
RB
122 }
123}
124// }}}
125
3e993f7a
FB
126// {{{ class UFC_Hrpid
127/** Filters users based on the hrpid of their profiles
128 * @param $val Either an hrpid, or a list of those
129 */
130class UFC_Hrpid implements UserFilterCondition
131{
132 private $hrpids;
133
61d1fd8b 134 public function __construct()
3e993f7a 135 {
61d1fd8b 136 $this->hrpids = pl_flatten(func_get_args());
3e993f7a
FB
137 }
138
139 public function buildCondition(PlFilter &$uf)
140 {
141 $uf->requireProfiles();
bde68f05 142 return XDB::format('p.hrpid IN {?}', $this->hrpids);
3e993f7a
FB
143 }
144}
145// }}}
146
f73a4f1b
RB
147// {{{ class UFC_Ip
148/** Filters users based on one of their last IPs
149 * @param $ip IP from which connection are checked
150 */
151class UFC_Ip implements UserFilterCondition
152{
153 private $ip;
154
155 public function __construct($ip)
156 {
157 $this->ip = $ip;
158 }
159
160 public function buildCondition(PlFilter &$uf)
161 {
162 $sub = $uf->addLoggerFilter();
163 $ip = ip_to_uint($this->ip);
164 return XDB::format($sub . '.ip = {?} OR ' . $sub . '.forward_ip = {?}', $ip, $ip);
165 }
166}
167// }}}
168
d7ddf29b
RB
169// {{{ class UFC_Comment
170class UFC_Comment implements UserFilterCondition
171{
172 private $text;
173
174 public function __construct($text)
175 {
176 $this->text = $text;
177 }
178
179 public function buildCondition(PlFilter &$uf)
180 {
181 $uf->requireProfiles();
7f26cd69 182 return $uf->getVisibilityCondition('p.freetext_pub') . ' AND p.freetext ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->text);
d7ddf29b
RB
183 }
184}
185// }}}
186
8363588b 187// {{{ class UFC_Promo
5d2e55c7 188/** Filters users based on promotion
53eae167
RB
189 * @param $comparison Comparison operator (>, =, ...)
190 * @param $grade Formation on which to restrict, UserFilter::DISPLAY for "any formation"
5d2e55c7 191 * @param $promo Promotion on which the filter is based
53eae167 192 */
a087cc8d
FB
193class UFC_Promo implements UserFilterCondition
194{
a087cc8d
FB
195
196 private $grade;
197 private $promo;
198 private $comparison;
199
200 public function __construct($comparison, $grade, $promo)
201 {
202 $this->grade = $grade;
203 $this->comparison = $comparison;
204 $this->promo = $promo;
38c6fe96
FB
205 if ($this->grade != UserFilter::DISPLAY) {
206 UserFilter::assertGrade($this->grade);
207 }
6c1e97ae 208 if ($this->grade == UserFilter::DISPLAY && $this->comparison != '=') {
999db5aa
RB
209 // XXX: we might try to guess the grade from the first char of the promo and forbid only '<= 2004', but allow '<= X2004'
210 Platal::page()->killError("Il n'est pas possible d'appliquer la comparaison '" . $this->comparison . "' aux promotions sans spécifier de formation (X/M/D)");
6c1e97ae 211 }
a087cc8d
FB
212 }
213
dcc63ed5 214 public function buildCondition(PlFilter &$uf)
a087cc8d 215 {
38c6fe96
FB
216 if ($this->grade == UserFilter::DISPLAY) {
217 $sub = $uf->addDisplayFilter();
1a23a02b 218 return XDB::format('pd' . $sub . '.promo ' . $this->comparison . ' {?}', $this->promo);
38c6fe96
FB
219 } else {
220 $sub = $uf->addEducationFilter(true, $this->grade);
221 $field = 'pe' . $sub . '.' . UserFilter::promoYear($this->grade);
222 return $field . ' IS NOT NULL AND ' . $field . ' ' . $this->comparison . ' ' . XDB::format('{?}', $this->promo);
223 }
784745ce
FB
224 }
225}
8363588b 226// }}}
784745ce 227
9e8bacfb
FB
228// {{{ class UFC_SchoolId
229/** Filters users based on their shoold identifier
230 * @param type Parameter type (Xorg, AX, School)
231 * @param value School id value
232 */
57f8776b 233class UFC_SchoolId implements UserFilterCondition
9e8bacfb
FB
234{
235 const AX = 'ax';
236 const Xorg = 'xorg';
237 const School = 'school';
238
239 private $type;
240 private $id;
241
242 static public function assertType($type)
243 {
244 if ($type != self::AX && $type != self::Xorg && $type != self::School) {
245 Platal::page()->killError("Type de matricule invalide: $type");
246 }
247 }
248
249 public function __construct($type, $id)
250 {
251 $this->type = $type;
252 $this->id = $id;
253 self::assertType($type);
254 }
255
256 public function buildCondition(PlFilter &$uf)
257 {
258 $uf->requireProfiles();
259 $id = $this->id;
260 $type = $this->type;
261 if ($type == self::School) {
262 $type = self::Xorg;
263 $id = Profile::getXorgId($id);
264 }
265 return XDB::format('p.' . $type . '_id = {?}', $id);
266 }
267}
268// }}}
269
fb3b6547 270// {{{ class UFC_EducationSchool
d7ddf29b
RB
271/** Filters users by formation
272 * @param $val The formation to search (either ID or array of IDs)
273 */
fb3b6547 274class UFC_EducationSchool implements UserFilterCondition
a7f8e48a 275{
d7ddf29b 276 private $val;
a7f8e48a 277
61d1fd8b 278 public function __construct()
a7f8e48a 279 {
61d1fd8b 280 $this->val = pl_flatten(func_get_args());
a7f8e48a
RB
281 }
282
283 public function buildCondition(PlFilter &$uf)
284 {
285 $sub = $uf->addEducationFilter();
bde68f05 286 return XDB::format('pe' . $sub . '.eduid IN {?}', $this->val);
a7f8e48a
RB
287 }
288}
289// }}}
290
fb3b6547
RB
291// {{{ class UFC_EducationDegree
292class UFC_EducationDegree implements UserFilterCondition
d7ddf29b
RB
293{
294 private $diploma;
295
61d1fd8b 296 public function __construct()
d7ddf29b 297 {
61d1fd8b 298 $this->diploma = pl_flatten(func_get_args());
d7ddf29b
RB
299 }
300
301 public function buildCondition(PlFilter &$uf)
302 {
303 $sub = $uf->addEducationFilter();
d115b6df 304 return XDB::format('pe' . $sub . '.degreeid IN {?}', $this->diploma);
d7ddf29b
RB
305 }
306}
307// }}}
308
fb3b6547
RB
309// {{{ class UFC_EducationField
310class UFC_EducationField implements UserFilterCondition
d7ddf29b
RB
311{
312 private $val;
313
61d1fd8b 314 public function __construct()
d7ddf29b 315 {
61d1fd8b 316 $this->val = pl_flatten(func_get_args());
d7ddf29b
RB
317 }
318
319 public function buildCondition(PlFilter &$uf)
320 {
321 $sub = $uf->addEducationFilter();
4290d54e 322 return XDB::format('pe' . $sub . '.fieldid IN {?}', $this->val);
d7ddf29b
RB
323 }
324}
325// }}}
326
8363588b 327// {{{ class UFC_Name
53eae167 328/** Filters users based on name
5d2e55c7 329 * @param $type Type of name field on which filtering is done (firstname, lastname...)
53eae167 330 * @param $text Text on which to filter
5d2e55c7 331 * @param $mode Flag indicating search type (prefix, suffix, with particule...)
53eae167 332 */
784745ce
FB
333class UFC_Name implements UserFilterCondition
334{
706f7a0f
RB
335 const EXACT = XDB::WILDCARD_EXACT; // 0x000
336 const PREFIX = XDB::WILDCARD_PREFIX; // 0x001
337 const SUFFIX = XDB::WILDCARD_SUFFIX; // 0x002
658b4c83 338 const CONTAINS = XDB::WILDCARD_CONTAINS; // 0x003
5bb60f74 339 const PARTICLE = 0x004;
658b4c83 340 const VARIANTS = 0x008;
784745ce
FB
341
342 private $type;
343 private $text;
344 private $mode;
345
346 public function __construct($type, $text, $mode)
347 {
348 $this->type = $type;
349 $this->text = $text;
350 $this->mode = $mode;
351 }
352
353 private function buildNameQuery($type, $variant, $where, UserFilter &$uf)
354 {
355 $sub = $uf->addNameFilter($type, $variant);
356 return str_replace('$ME', 'pn' . $sub, $where);
357 }
358
dcc63ed5 359 public function buildCondition(PlFilter &$uf)
784745ce
FB
360 {
361 $left = '$ME.name';
784745ce
FB
362 if (($this->mode & self::PARTICLE) == self::PARTICLE) {
363 $left = 'CONCAT($ME.particle, \' \', $ME.name)';
364 }
658b4c83
RB
365 $right = XDB::formatWildcards($this->mode & self::CONTAINS, $this->text);
366
367 $cond = $left . $right;
784745ce 368 $conds = array($this->buildNameQuery($this->type, null, $cond, $uf));
913a4e90
RB
369 if (($this->mode & self::VARIANTS) != 0 && isset(Profile::$name_variants[$this->type])) {
370 foreach (Profile::$name_variants[$this->type] as $var) {
784745ce
FB
371 $conds[] = $this->buildNameQuery($this->type, $var, $cond, $uf);
372 }
373 }
374 return implode(' OR ', $conds);
a087cc8d
FB
375 }
376}
8363588b 377// }}}
a087cc8d 378
40585144
RB
379// {{{ class UFC_NameTokens
380/** Selects users based on tokens in their name (for quicksearch)
381 * @param $tokens An array of tokens to search
382 * @param $flags Flags the tokens must have (e.g 'public' for public search)
383 * @param $soundex (bool) Whether those tokens are fulltext or soundex
384 */
385class UFC_NameTokens implements UserFilterCondition
386{
387 /* Flags */
388 const FLAG_PUBLIC = 'public';
389
390 private $tokens;
391 private $flags;
392 private $soundex;
79a0b464 393 private $exact;
40585144 394
79a0b464 395 public function __construct($tokens, $flags = array(), $soundex = false, $exact = false)
40585144 396 {
a867dfba
RB
397 if (is_array($tokens)) {
398 $this->tokens = $tokens;
399 } else {
400 $this->tokens = array($tokens);
401 }
40585144
RB
402 if (is_array($flags)) {
403 $this->flags = $flags;
404 } else {
405 $this->flags = array($flags);
406 }
407 $this->soundex = $soundex;
79a0b464 408 $this->exact = $exact;
40585144
RB
409 }
410
dcc63ed5 411 public function buildCondition(PlFilter &$uf)
40585144 412 {
40585144 413 $conds = array();
2a93b634
RB
414 foreach ($this->tokens as $i => $token) {
415 $sub = $uf->addNameTokensFilter($token);
416 if ($this->soundex) {
417 $c = XDB::format($sub . '.soundex = {?}', $token);
418 } else if ($this->exact) {
419 $c = XDB::format($sub . '.token = {?}', $token);
420 } else {
421 $c = $sub . '.token ' . XDB::formatWildcards(XDB::WILDCARD_PREFIX, $token);
40585144 422 }
2a93b634
RB
423 if ($this->flags != null) {
424 $c .= XDB::format(' AND ' . $sub . '.flags IN {?}', $this->flags);
425 }
426 $conds[] = $c;
40585144
RB
427 }
428
429 return implode(' AND ', $conds);
430 }
431}
432// }}}
433
0fb3713c
RB
434// {{{ class UFC_Nationality
435class UFC_Nationality implements UserFilterCondition
436{
d7ddf29b 437 private $val;
0fb3713c 438
61d1fd8b 439 public function __construct()
0fb3713c 440 {
61d1fd8b 441 $this->val = pl_flatten(func_get_args());
0fb3713c
RB
442 }
443
444 public function buildCondition(PlFilter &$uf)
445 {
d7ddf29b
RB
446 $uf->requireProfiles();
447 $nat = XDB::formatArray($this->val);
448 $conds = array(
449 'p.nationality1 IN ' . $nat,
450 'p.nationality2 IN ' . $nat,
451 'p.nationality3 IN ' . $nat,
452 );
453 return implode(' OR ', $conds);
0fb3713c
RB
454 }
455}
456// }}}
457
8363588b 458// {{{ class UFC_Dead
53eae167
RB
459/** Filters users based on death date
460 * @param $comparison Comparison operator
8fcb783a 461 * @param $date Date to which death date should be compared (DateTime object, string or timestamp)
53eae167 462 */
4927ee54
FB
463class UFC_Dead implements UserFilterCondition
464{
38c6fe96
FB
465 private $comparison;
466 private $date;
467
468 public function __construct($comparison = null, $date = null)
4927ee54 469 {
38c6fe96 470 $this->comparison = $comparison;
a0d47f5c 471 $this->date = make_datetime($date);
4927ee54
FB
472 }
473
dcc63ed5 474 public function buildCondition(PlFilter &$uf)
4927ee54 475 {
d7ddf29b 476 $uf->requireProfiles();
38c6fe96
FB
477 $str = 'p.deathdate IS NOT NULL';
478 if (!is_null($this->comparison)) {
8fcb783a 479 $str .= ' AND p.deathdate ' . $this->comparison . ' ' . XDB::format('{?}', $this->date->format('Y-m-d'));
4927ee54 480 }
38c6fe96 481 return $str;
4927ee54
FB
482 }
483}
8363588b 484// }}}
4927ee54 485
8363588b 486// {{{ class UFC_Registered
53eae167
RB
487/** Filters users based on registration state
488 * @param $active Whether we want to use only "active" users (i.e with a valid redirection)
489 * @param $comparison Comparison operator
490 * @param $date Date to which users registration date should be compared
491 */
4927ee54
FB
492class UFC_Registered implements UserFilterCondition
493{
494 private $active;
38c6fe96
FB
495 private $comparison;
496 private $date;
497
498 public function __construct($active = false, $comparison = null, $date = null)
4927ee54 499 {
b2e8fc54 500 $this->active = $active;
38c6fe96 501 $this->comparison = $comparison;
a0d47f5c 502 $this->date = make_datetime($date);
4927ee54
FB
503 }
504
dcc63ed5 505 public function buildCondition(PlFilter &$uf)
4927ee54 506 {
d7ddf29b 507 $uf->requireAccounts();
4927ee54 508 if ($this->active) {
93b0da52 509 $date = '$UID IS NOT NULL AND a.state = \'active\'';
4927ee54 510 } else {
93b0da52 511 $date = '$UID IS NOT NULL AND a.state != \'pending\'';
38c6fe96
FB
512 }
513 if (!is_null($this->comparison)) {
c9c74e4f 514 $date .= ' AND a.registration_date != \'0000-00-00 00:00:00\' AND a.registration_date ' . $this->comparison . ' ' . XDB::format('{?}', $this->date->format('Y-m-d'));
4927ee54 515 }
38c6fe96 516 return $date;
4927ee54
FB
517 }
518}
8363588b 519// }}}
4927ee54 520
8363588b 521// {{{ class UFC_ProfileUpdated
53eae167
RB
522/** Filters users based on profile update date
523 * @param $comparison Comparison operator
524 * @param $date Date to which profile update date must be compared
525 */
7e735012
FB
526class UFC_ProfileUpdated implements UserFilterCondition
527{
528 private $comparison;
529 private $date;
530
531 public function __construct($comparison = null, $date = null)
532 {
533 $this->comparison = $comparison;
534 $this->date = $date;
535 }
536
dcc63ed5 537 public function buildCondition(PlFilter &$uf)
7e735012 538 {
d7ddf29b 539 $uf->requireProfiles();
7e735012
FB
540 return 'p.last_change ' . $this->comparison . XDB::format(' {?}', date('Y-m-d H:i:s', $this->date));
541 }
542}
8363588b 543// }}}
7e735012 544
8363588b 545// {{{ class UFC_Birthday
53eae167
RB
546/** Filters users based on next birthday date
547 * @param $comparison Comparison operator
548 * @param $date Date to which users next birthday date should be compared
549 */
7e735012
FB
550class UFC_Birthday implements UserFilterCondition
551{
552 private $comparison;
553 private $date;
554
555 public function __construct($comparison = null, $date = null)
556 {
557 $this->comparison = $comparison;
558 $this->date = $date;
559 }
560
dcc63ed5 561 public function buildCondition(PlFilter &$uf)
7e735012 562 {
d7ddf29b 563 $uf->requireProfiles();
7e735012
FB
564 return 'p.next_birthday ' . $this->comparison . XDB::format(' {?}', date('Y-m-d', $this->date));
565 }
566}
8363588b 567// }}}
7e735012 568
8363588b 569// {{{ class UFC_Sex
53eae167
RB
570/** Filters users based on sex
571 * @parm $sex One of User::GENDER_MALE or User::GENDER_FEMALE, for selecting users
572 */
4927ee54
FB
573class UFC_Sex implements UserFilterCondition
574{
575 private $sex;
576 public function __construct($sex)
577 {
578 $this->sex = $sex;
579 }
580
dcc63ed5 581 public function buildCondition(PlFilter &$uf)
4927ee54
FB
582 {
583 if ($this->sex != User::GENDER_MALE && $this->sex != User::GENDER_FEMALE) {
584 return self::COND_FALSE;
585 } else {
d7ddf29b 586 $uf->requireProfiles();
24e08e33 587 return XDB::format('p.sex = {?}', $this->sex == User::GENDER_FEMALE ? 'female' : 'male');
4927ee54
FB
588 }
589 }
590}
8363588b 591// }}}
4927ee54 592
8363588b 593// {{{ class UFC_Group
53eae167 594/** Filters users based on group membership
5d2e55c7
RB
595 * @param $group Group whose members we are selecting
596 * @param $anim Whether to restrict selection to animators of that group
53eae167 597 */
4927ee54
FB
598class UFC_Group implements UserFilterCondition
599{
600 private $group;
5d2e55c7
RB
601 private $anim;
602 public function __construct($group, $anim = false)
4927ee54
FB
603 {
604 $this->group = $group;
5d2e55c7 605 $this->anim = $anim;
4927ee54
FB
606 }
607
dcc63ed5 608 public function buildCondition(PlFilter &$uf)
4927ee54 609 {
7f26cd69
RB
610 // Groups have AX visibility.
611 if ($uf->getVisibilityLevel() == ProfileVisibility::VIS_PUBLIC) {
9f169a65 612 return PlFilter::COND_TRUE;
7f26cd69 613 }
4927ee54
FB
614 $sub = $uf->addGroupFilter($this->group);
615 $where = 'gpm' . $sub . '.perms IS NOT NULL';
5d2e55c7 616 if ($this->anim) {
4927ee54
FB
617 $where .= ' AND gpm' . $sub . '.perms = \'admin\'';
618 }
619 return $where;
620 }
621}
8363588b 622// }}}
4927ee54 623
0fb3713c 624// {{{ class UFC_Binet
d7ddf29b
RB
625/** Selects users based on their belonging to a given (list of) binet
626 * @param $binet either a binet_id or an array of binet_ids
627 */
0fb3713c
RB
628class UFC_Binet implements UserFilterCondition
629{
d7ddf29b 630 private $val;
0fb3713c 631
61d1fd8b 632 public function __construct()
0fb3713c 633 {
61d1fd8b 634 $this->val = pl_flatten(func_get_args());
0fb3713c
RB
635 }
636
637 public function buildCondition(PlFilter &$uf)
638 {
7f26cd69
RB
639 // Binets are private.
640 if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) {
9f169a65 641 return PlFilter::COND_TRUE;
7f26cd69 642 }
d7ddf29b 643 $sub = $uf->addBinetsFilter();
bde68f05 644 return XDB::format($sub . '.binet_id IN {?}', $this->val);
a7f8e48a
RB
645 }
646}
647// }}}
648
649// {{{ class UFC_Section
46e88fe3
RB
650/** Selects users based on section
651 * @param $section ID of the section
652 */
a7f8e48a
RB
653class UFC_Section implements UserFilterCondition
654{
655 private $section;
656
61d1fd8b 657 public function __construct()
a7f8e48a 658 {
61d1fd8b 659 $this->section = pl_flatten(func_get_args());
a7f8e48a
RB
660 }
661
662 public function buildCondition(PlFilter &$uf)
663 {
7f26cd69
RB
664 // Sections are private.
665 if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) {
9f169a65 666 return PlFilter::COND_TRUE;
7f26cd69 667 }
a7f8e48a 668 $uf->requireProfiles();
61d1fd8b 669 return XDB::format('p.section IN {?}', $this->section);
0fb3713c
RB
670 }
671}
672// }}}
673
8363588b 674// {{{ class UFC_Email
2d6329a2 675/** Filters users based on an email or a list of emails
53eae167
RB
676 * @param $emails List of emails whose owner must be selected
677 */
2d6329a2 678class UFC_Email implements UserFilterCondition
21401768
FB
679{
680 private $emails;
2d6329a2 681 public function __construct()
21401768 682 {
61d1fd8b 683 $this->emails = pl_flatten(func_get_args());
21401768
FB
684 }
685
dcc63ed5 686 public function buildCondition(PlFilter &$uf)
21401768 687 {
2d6329a2
FB
688 $foreign = array();
689 $virtual = array();
690 $aliases = array();
21401768
FB
691 $cond = array();
692
693 if (count($this->emails) == 0) {
dcc63ed5 694 return PlFilterCondition::COND_TRUE;
21401768
FB
695 }
696
697 foreach ($this->emails as $entry) {
698 if (User::isForeignEmailAddress($entry)) {
2d6329a2 699 $foreign[] = $entry;
21401768 700 } else if (User::isVirtualEmailAddress($entry)) {
2d6329a2 701 $virtual[] = $entry;
21401768 702 } else {
21401768 703 @list($user, $domain) = explode('@', $entry);
2d6329a2 704 $aliases[] = $user;
21401768
FB
705 }
706 }
2d6329a2
FB
707
708 if (count($foreign) > 0) {
709 $sub = $uf->addEmailRedirectFilter($foreign);
bde68f05 710 $cond[] = XDB::format('e' . $sub . '.email IS NOT NULL OR a.email IN {?}', $foreign);
2d6329a2
FB
711 }
712 if (count($virtual) > 0) {
713 $sub = $uf->addVirtualEmailFilter($virtual);
714 $cond[] = 'vr' . $sub . '.redirect IS NOT NULL';
715 }
716 if (count($aliases) > 0) {
717 $sub = $uf->addAliasFilter($aliases);
718 $cond[] = 'al' . $sub . '.alias IS NOT NULL';
719 }
21401768
FB
720 return '(' . implode(') OR (', $cond) . ')';
721 }
722}
8363588b 723// }}}
d865c296 724
8363588b 725// {{{ class UFC_Address
2b9ca54d 726abstract class UFC_Address implements UserFilterCondition
c4b24511 727{
2b9ca54d 728 /** Valid address type ('hq' is reserved for company addresses)
036d1637 729 */
2b9ca54d
RB
730 const TYPE_HOME = 1;
731 const TYPE_PRO = 2;
732 const TYPE_ANY = 3;
c4b24511 733
2b9ca54d 734 /** Text for these types
036d1637 735 */
2b9ca54d
RB
736 protected static $typetexts = array(
737 self::TYPE_HOME => 'home',
738 self::TYPE_PRO => 'pro',
739 );
740
741 protected $type;
c4b24511 742
036d1637
RB
743 /** Flags for addresses
744 */
745 const FLAG_CURRENT = 0x0001;
746 const FLAG_TEMP = 0x0002;
747 const FLAG_SECOND = 0x0004;
748 const FLAG_MAIL = 0x0008;
749 const FLAG_CEDEX = 0x0010;
750
751 // Binary OR of those flags
752 const FLAG_ANY = 0x001F;
753
754 /** Text of these flags
755 */
2b9ca54d 756 protected static $flagtexts = array(
036d1637
RB
757 self::FLAG_CURRENT => 'current',
758 self::FLAG_TEMP => 'temporary',
759 self::FLAG_SECOND => 'secondary',
760 self::FLAG_MAIL => 'mail',
761 self::FLAG_CEDEX => 'cedex',
762 );
763
2b9ca54d
RB
764 protected $flags;
765
766 public function __construct($type = null, $flags = null)
767 {
768 $this->type = $type;
769 $this->flags = $flags;
770 }
771
7f26cd69 772 protected function initConds($sub, $vis_cond)
2b9ca54d 773 {
7f26cd69
RB
774 $conds = array($vis_cond);
775
2b9ca54d
RB
776 $types = array();
777 foreach (self::$typetexts as $flag => $type) {
778 if ($flag & $this->type) {
779 $types[] = $type;
780 }
781 }
782 if (count($types)) {
6b140032 783 $conds[] = XDB::format($sub . '.type IN {?}', $types);
2b9ca54d
RB
784 }
785
786 if ($this->flags != self::FLAG_ANY) {
787 foreach(self::$flagtexts as $flag => $text) {
788 if ($flag & $this->flags) {
789 $conds[] = 'FIND_IN_SET(' . XDB::format('{?}', $text) . ', ' . $sub . '.flags)';
790 }
791 }
792 }
793 return $conds;
794 }
795
796}
797// }}}
798
799// {{{ class UFC_AddressText
800/** Select users based on their address, using full text search
801 * @param $text Text for filter in fulltext search
658b4c83 802 * @param $textSearchMode Mode for search (one of XDB::WILDCARD_*)
2b9ca54d
RB
803 * @param $type Filter on address type
804 * @param $flags Filter on address flags
805 * @param $country Filter on address country
806 * @param $locality Filter on address locality
807 */
808class UFC_AddressText extends UFC_Address
809{
2b9ca54d 810
036d1637 811 private $text;
2b9ca54d
RB
812 private $textSearchMode;
813
658b4c83 814 public function __construct($text = null, $textSearchMode = XDB::WILDCARD_CONTAINS,
2b9ca54d
RB
815 $type = null, $flags = self::FLAG_ANY, $country = null, $locality = null)
816 {
817 parent::__construct($type, $flags);
818 $this->text = $text;
819 $this->textSearchMode = $textSearchMode;
820 $this->country = $country;
821 $this->locality = $locality;
822 }
823
824 private function mkMatch($txt)
825 {
658b4c83 826 return XDB::formatWildcards($this->textSearchMode, $txt);
2b9ca54d
RB
827 }
828
829 public function buildCondition(PlFilter &$uf)
830 {
831 $sub = $uf->addAddressFilter();
7f26cd69 832 $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub'));
2b9ca54d
RB
833 if ($this->text != null) {
834 $conds[] = $sub . '.text' . $this->mkMatch($this->text);
835 }
836
837 if ($this->country != null) {
838 $subc = $uf->addAddressCountryFilter();
839 $subconds = array();
840 $subconds[] = $subc . '.country' . $this->mkMatch($this->country);
841 $subconds[] = $subc . '.countryFR' . $this->mkMatch($this->country);
842 $conds[] = implode(' OR ', $subconds);
843 }
844
845 if ($this->locality != null) {
846 $subl = $uf->addAddressLocalityFilter();
847 $conds[] = $subl . '.name' . $this->mkMatch($this->locality);
848 }
849
850 return implode(' AND ', $conds);
851 }
852}
853// }}}
854
46e88fe3 855// {{{ class UFC_AddressField
2b9ca54d 856/** Filters users based on their address,
46e88fe3
RB
857 * @param $val Either a code for one of the fields, or an array of such codes
858 * @param $fieldtype The type of field to look for
2b9ca54d
RB
859 * @param $type Filter on address type
860 * @param $flags Filter on address flags
2b9ca54d 861 */
46e88fe3 862class UFC_AddressField extends UFC_Address
2b9ca54d 863{
46e88fe3
RB
864 const FIELD_COUNTRY = 1;
865 const FIELD_ADMAREA = 2;
866 const FIELD_SUBADMAREA = 3;
867 const FIELD_LOCALITY = 4;
868 const FIELD_ZIPCODE = 5;
869
2b9ca54d
RB
870 /** Data of the filter
871 */
46e88fe3
RB
872 private $val;
873 private $fieldtype;
036d1637 874
46e88fe3 875 public function __construct($val, $fieldtype, $type = null, $flags = self::FLAG_ANY)
036d1637 876 {
2b9ca54d 877 parent::__construct($type, $flags);
46e88fe3
RB
878
879 if (!is_array($val)) {
880 $val = array($val);
881 }
882 $this->val = $val;
883 $this->fieldtype = $fieldtype;
c4b24511
RB
884 }
885
dcc63ed5 886 public function buildCondition(PlFilter &$uf)
c4b24511 887 {
036d1637 888 $sub = $uf->addAddressFilter();
7f26cd69 889 $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub'));
036d1637 890
46e88fe3
RB
891 switch ($this->fieldtype) {
892 case self::FIELD_COUNTRY:
893 $field = 'countryId';
894 break;
895 case self::FIELD_ADMAREA:
896 $field = 'administrativeAreaId';
897 break;
898 case self::FIELD_SUBADMAREA:
899 $field = 'subAdministrativeAreaId';
900 break;
901 case self::FIELD_LOCALITY:
902 $field = 'localityId';
903 break;
904 case self::FIELD_ZIPCODE:
905 $field = 'postalCode';
906 break;
907 default:
61f61261 908 Platal::page()->killError('Invalid address field type: ' . $this->fieldtype);
46e88fe3 909 }
bde68f05 910 $conds[] = XDB::format($sub . '.' . $field . ' IN {?}', $this->val);
036d1637
RB
911
912 return implode(' AND ', $conds);
c4b24511
RB
913 }
914}
8363588b 915// }}}
c4b24511 916
8363588b 917// {{{ class UFC_Corps
4083b126
RB
918/** Filters users based on the corps they belong to
919 * @param $corps Corps we are looking for (abbreviation)
920 * @param $type Whether we search for original or current corps
921 */
922class UFC_Corps implements UserFilterCondition
923{
5d2e55c7
RB
924 const CURRENT = 1;
925 const ORIGIN = 2;
4083b126
RB
926
927 private $corps;
928 private $type;
929
930 public function __construct($corps, $type = self::CURRENT)
931 {
932 $this->corps = $corps;
933 $this->type = $type;
934 }
935
dcc63ed5 936 public function buildCondition(PlFilter &$uf)
4083b126 937 {
5d2e55c7
RB
938 /** Tables shortcuts:
939 * pc for profile_corps,
4083b126
RB
940 * pceo for profile_corps_enum - orginal
941 * pcec for profile_corps_enum - current
942 */
943 $sub = $uf->addCorpsFilter($this->type);
944 $cond = $sub . '.abbreviation = ' . $corps;
7f26cd69 945 $cond .= ' AND ' . $uf->getVisibilityCondition($sub . '.corps_pub');
4083b126
RB
946 return $cond;
947 }
948}
8363588b 949// }}}
4083b126 950
8363588b 951// {{{ class UFC_Corps_Rank
4083b126
RB
952/** Filters users based on their rank in the corps
953 * @param $rank Rank we are looking for (abbreviation)
954 */
955class UFC_Corps_Rank implements UserFilterCondition
956{
957 private $rank;
958 public function __construct($rank)
959 {
960 $this->rank = $rank;
961 }
962
dcc63ed5 963 public function buildCondition(PlFilter &$uf)
4083b126 964 {
5d2e55c7 965 /** Tables shortcuts:
7f26cd69 966 * pc for profile_corps
4083b126
RB
967 * pcr for profile_corps_rank
968 */
969 $sub = $uf->addCorpsRankFilter();
970 $cond = $sub . '.abbreviation = ' . $rank;
7f26cd69
RB
971 // XXX(x2006barrois): find a way to get rid of that hardcoded
972 // reference to 'pc'.
973 $cond .= ' AND ' . $uf->getVisibilityCondition('pc.corps_pub');
4083b126
RB
974 return $cond;
975 }
976}
8363588b 977// }}}
4083b126 978
6a99c3ac
RB
979// {{{ class UFC_Job_Company
980/** Filters users based on the company they belong to
981 * @param $type The field being searched (self::JOBID, self::JOBNAME or self::JOBACRONYM)
982 * @param $value The searched value
983 */
4e2f2ad2 984class UFC_Job_Company implements UserFilterCondition
6a99c3ac
RB
985{
986 const JOBID = 'id';
987 const JOBNAME = 'name';
988 const JOBACRONYM = 'acronym';
989
990 private $type;
991 private $value;
992
993 public function __construct($type, $value)
994 {
995 $this->assertType($type);
996 $this->type = $type;
997 $this->value = $value;
998 }
999
1000 private function assertType($type)
1001 {
1002 if ($type != self::JOBID && $type != self::JOBNAME && $type != self::JOBACRONYM) {
5d2e55c7 1003 Platal::page()->killError("Type de recherche non valide.");
6a99c3ac
RB
1004 }
1005 }
1006
dcc63ed5 1007 public function buildCondition(PlFilter &$uf)
6a99c3ac
RB
1008 {
1009 $sub = $uf->addJobCompanyFilter();
412e2e0f 1010 $cond = $sub . '.' . $this->type . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value);
7f26cd69
RB
1011 $jsub = $uf->addJobFilter();
1012 $cond .= ' AND ' . $uf->getVisibilityCondition($jsub . '.pub');
6a99c3ac
RB
1013 return $cond;
1014 }
1015}
1016// }}}
1017
3ac45f10
PC
1018// {{{ class UFC_Job_Terms
1019/** Filters users based on the job terms they assigned to one of their
1020 * jobs.
1021 * @param $val The ID of the job term, or an array of such IDs
1022 */
1023class UFC_Job_Terms implements UserFilterCondition
1024{
1025 private $val;
1026
1027 public function __construct($val)
1028 {
1029 if (!is_array($val)) {
1030 $val = array($val);
1031 }
1032 $this->val = $val;
1033 }
1034
1035 public function buildCondition(PlFilter &$uf)
1036 {
1037 $sub = $uf->addJobTermsFilter(count($this->val));
1038 $conditions = array();
1039 foreach ($this->val as $i => $jtid) {
4ec03752 1040 $conditions[] = $sub[$i] . '.jtid_1 = ' . XDB::escape($jtid);
3ac45f10 1041 }
7f26cd69
RB
1042 $jsub = $uf->addJobFilter();
1043 $conditions[] = $uf->getVisibilityCondition($jsub . '.pub');
3ac45f10
PC
1044 return implode(' AND ', $conditions);
1045 }
1046}
1047// }}}
1048
6a99c3ac
RB
1049// {{{ class UFC_Job_Description
1050/** Filters users based on their job description
1051 * @param $description The text being searched for
da40b2a4 1052 * @param $fields The fields to search for (CV, user-defined)
6a99c3ac 1053 */
4e2f2ad2 1054class UFC_Job_Description implements UserFilterCondition
6a99c3ac
RB
1055{
1056
6a99c3ac
RB
1057 private $description;
1058 private $fields;
1059
01cc5f9e 1060 public function __construct($description, $fields)
6a99c3ac
RB
1061 {
1062 $this->fields = $fields;
1063 $this->description = $description;
1064 }
1065
dcc63ed5 1066 public function buildCondition(PlFilter &$uf)
6a99c3ac
RB
1067 {
1068 $conds = array();
7f26cd69
RB
1069
1070 $jsub = $uf->addJobFilter();
1071 // CV is private => if only CV requested, and not private,
1072 // don't do anything. Otherwise restrict to standard job visibility.
9f169a65
RB
1073 if ($this->fields == UserFilter::JOB_CV) {
1074 if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) {
1075 return PlFilter::COND_TRUE;
1076 }
1077 } else {
7f26cd69
RB
1078 $conds[] = $uf->getVisibilityCondition($jsub . '.pub');
1079 }
1080
6a99c3ac 1081 if ($this->fields & UserFilter::JOB_USERDEFINED) {
7f26cd69 1082 $conds[] = $jsub . '.description ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description);
6a99c3ac 1083 }
7f26cd69 1084 if ($this->fields & UserFilter::JOB_CV && $uf->getVisibilityLevel == ProfileVisibility::VIS_PRIVATE) {
01cc5f9e 1085 $uf->requireProfiles();
658b4c83 1086 $conds[] = 'p.cv ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description);
01cc5f9e 1087 }
6a99c3ac
RB
1088 return implode(' OR ', $conds);
1089 }
1090}
1091// }}}
1092
0a2e9c74
RB
1093// {{{ class UFC_Networking
1094/** Filters users based on network identity (IRC, ...)
1095 * @param $type Type of network (-1 for any)
1096 * @param $value Value to search
1097 */
4e2f2ad2 1098class UFC_Networking implements UserFilterCondition
0a2e9c74
RB
1099{
1100 private $type;
1101 private $value;
1102
1103 public function __construct($type, $value)
1104 {
1105 $this->type = $type;
1106 $this->value = $value;
1107 }
1108
dcc63ed5 1109 public function buildCondition(PlFilter &$uf)
0a2e9c74
RB
1110 {
1111 $sub = $uf->addNetworkingFilter();
1112 $conds = array();
7f26cd69 1113 $conds[] = $uf->getVisibilityCondition($sub . '.pub');
658b4c83 1114 $conds[] = $sub . '.address ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value);
0a2e9c74 1115 if ($this->type != -1) {
1f5cd004 1116 $conds[] = $sub . '.nwid = ' . XDB::format('{?}', $this->type);
0a2e9c74
RB
1117 }
1118 return implode(' AND ', $conds);
1119 }
1120}
1121// }}}
1122
6d62969e
RB
1123// {{{ class UFC_Phone
1124/** Filters users based on their phone number
1125 * @param $num_type Type of number (pro/user/home)
1126 * @param $phone_type Type of phone (fixed/mobile/fax)
1127 * @param $number Phone number
1128 */
4e2f2ad2 1129class UFC_Phone implements UserFilterCondition
6d62969e
RB
1130{
1131 const NUM_PRO = 'pro';
1132 const NUM_USER = 'user';
1133 const NUM_HOME = 'address';
1134 const NUM_ANY = 'any';
1135
1136 const PHONE_FIXED = 'fixed';
1137 const PHONE_MOBILE = 'mobile';
1138 const PHONE_FAX = 'fax';
1139 const PHONE_ANY = 'any';
1140
1141 private $num_type;
1142 private $phone_type;
1143 private $number;
1144
1145 public function __construct($number, $num_type = self::NUM_ANY, $phone_type = self::PHONE_ANY)
1146 {
da0a9c5a 1147 $phone = new Phone(array('display' => $number));
0b6c8b36
SJ
1148 $phone->format();
1149 $this->number = $phone->search();
6d62969e 1150 $this->num_type = $num_type;
0b6c8b36 1151 $this->phone_type = $phone_type;
6d62969e
RB
1152 }
1153
dcc63ed5 1154 public function buildCondition(PlFilter &$uf)
6d62969e
RB
1155 {
1156 $sub = $uf->addPhoneFilter();
1157 $conds = array();
7f26cd69
RB
1158
1159 $conds[] = $uf->getVisibilityCondition($sub . '.pub');
1160
6d62969e
RB
1161 $conds[] = $sub . '.search_tel = ' . XDB::format('{?}', $this->number);
1162 if ($this->num_type != self::NUM_ANY) {
1163 $conds[] = $sub . '.link_type = ' . XDB::format('{?}', $this->num_type);
1164 }
1165 if ($this->phone_type != self::PHONE_ANY) {
1166 $conds[] = $sub . '.tel_type = ' . XDB::format('{?}', $this->phone_type);
1167 }
1168 return implode(' AND ', $conds);
1169 }
1170}
1171// }}}
1172
ceb512d2
RB
1173// {{{ class UFC_Medal
1174/** Filters users based on their medals
1175 * @param $medal ID of the medal
1176 * @param $grade Grade of the medal (null for 'any')
1177 */
4e2f2ad2 1178class UFC_Medal implements UserFilterCondition
ceb512d2
RB
1179{
1180 private $medal;
1181 private $grade;
1182
1183 public function __construct($medal, $grade = null)
1184 {
1185 $this->medal = $medal;
1186 $this->grade = $grade;
1187 }
1188
dcc63ed5 1189 public function buildCondition(PlFilter &$uf)
ceb512d2
RB
1190 {
1191 $conds = array();
7f26cd69
RB
1192
1193 // This will require profiles => table 'p' will be available.
ceb512d2 1194 $sub = $uf->addMedalFilter();
7f26cd69
RB
1195
1196 $conds[] = $uf->getVisibilityCondition('p.medals_pub');
1197
ceb512d2
RB
1198 $conds[] = $sub . '.mid = ' . XDB::format('{?}', $this->medal);
1199 if ($this->grade != null) {
1200 $conds[] = $sub . '.gid = ' . XDB::format('{?}', $this->grade);
1201 }
1202 return implode(' AND ', $conds);
1203 }
1204}
1205// }}}
1206
470d14f6
FB
1207// {{{ class UFC_Photo
1208/** Filters profiles with photo
1209 */
1210class UFC_Photo implements UserFilterCondition
1211{
1212 public function buildCondition(PlFilter &$uf)
1213 {
7f26cd69
RB
1214 $sub = $uf->addPhotoFilter();
1215 return $sub . '.attach IS NOT NULL AND ' . $uf->getVisibilityCondition($sub . '.pub');
470d14f6
FB
1216 }
1217}
1218// }}}
1219
96f01fba
RB
1220// {{{ class UFC_Mentor
1221class UFC_Mentor implements UserFilterCondition
1222{
1223 public function buildCondition(PlFilter &$uf)
1224 {
1225 $sub = $uf->addMentorFilter(UserFilter::MENTOR);
1226 return $sub . '.expertise IS NOT NULL';
1227 }
1228}
1229// }}}
1230
1231
671b7073
RB
1232// {{{ class UFC_Mentor_Expertise
1233/** Filters users by mentoring expertise
1234 * @param $expertise Domain of expertise
1235 */
4e2f2ad2 1236class UFC_Mentor_Expertise implements UserFilterCondition
671b7073
RB
1237{
1238 private $expertise;
1239
1240 public function __construct($expertise)
1241 {
1242 $this->expertise = $expertise;
1243 }
1244
dcc63ed5 1245 public function buildCondition(PlFilter &$uf)
671b7073
RB
1246 {
1247 $sub = $uf->addMentorFilter(UserFilter::MENTOR_EXPERTISE);
658b4c83 1248 return $sub . '.expertise ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->expertise);
671b7073
RB
1249 }
1250}
1251// }}}
1252
1253// {{{ class UFC_Mentor_Country
1254/** Filters users by mentoring country
1255 * @param $country Two-letters code of country being searched
1256 */
4e2f2ad2 1257class UFC_Mentor_Country implements UserFilterCondition
671b7073
RB
1258{
1259 private $country;
1260
61d1fd8b 1261 public function __construct()
671b7073 1262 {
61d1fd8b 1263 $this->country = pl_flatten(func_get_args());
671b7073
RB
1264 }
1265
dcc63ed5 1266 public function buildCondition(PlFilter &$uf)
671b7073
RB
1267 {
1268 $sub = $uf->addMentorFilter(UserFilter::MENTOR_COUNTRY);
61d1fd8b 1269 return $sub . '.country IN ' . XDB::format('{?}', $this->country);
671b7073
RB
1270 }
1271}
1272// }}}
1273
459e6f81
PC
1274// {{{ class UFC_Mentor_Terms
1275/** Filters users based on the job terms they used in mentoring.
1276 * @param $val The ID of the job term, or an array of such IDs
1277 */
1278class UFC_Mentor_Terms implements UserFilterCondition
1279{
1280 private $val;
1281
1282 public function __construct($val)
1283 {
1284 $this->val = $val;
1285 }
1286
1287 public function buildCondition(PlFilter &$uf)
1288 {
1289 $sub = $uf->addMentorFilter(UserFilter::MENTOR_TERM);
1290 return $sub . '.jtid_1 = ' . XDB::escape($this->val);
1291 }
1292}
1293// }}}
1294
8363588b 1295// {{{ class UFC_UserRelated
5d2e55c7 1296/** Filters users based on a relation toward a user
53eae167
RB
1297 * @param $user User to which searched users are related
1298 */
4e7bf1e0 1299abstract class UFC_UserRelated implements UserFilterCondition
3f42a6ad 1300{
009b8ab7
FB
1301 protected $user;
1302 public function __construct(PlUser &$user)
1303 {
1304 $this->user =& $user;
3f42a6ad 1305 }
4e7bf1e0 1306}
8363588b 1307// }}}
3f42a6ad 1308
8363588b 1309// {{{ class UFC_Contact
5d2e55c7 1310/** Filters users who belong to selected user's contacts
53eae167 1311 */
4e7bf1e0
FB
1312class UFC_Contact extends UFC_UserRelated
1313{
dcc63ed5 1314 public function buildCondition(PlFilter &$uf)
3f42a6ad 1315 {
009b8ab7 1316 $sub = $uf->addContactFilter($this->user->id());
3f42a6ad
FB
1317 return 'c' . $sub . '.contact IS NOT NULL';
1318 }
1319}
8363588b 1320// }}}
3f42a6ad 1321
8363588b 1322// {{{ class UFC_WatchRegistration
53eae167
RB
1323/** Filters users being watched by selected user
1324 */
4e7bf1e0
FB
1325class UFC_WatchRegistration extends UFC_UserRelated
1326{
dcc63ed5 1327 public function buildCondition(PlFilter &$uf)
4e7bf1e0 1328 {
a87530ea 1329 if (!$this->user->watchType('registration')) {
dcc63ed5 1330 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
1331 }
1332 $uids = $this->user->watchUsers();
1333 if (count($uids) == 0) {
dcc63ed5 1334 return PlFilterCondition::COND_FALSE;
009b8ab7 1335 } else {
93b0da52 1336 return XDB::format('$UID IN {?}', $uids);
009b8ab7 1337 }
4e7bf1e0
FB
1338 }
1339}
8363588b 1340// }}}
4e7bf1e0 1341
8363588b 1342// {{{ class UFC_WatchPromo
53eae167
RB
1343/** Filters users belonging to a promo watched by selected user
1344 * @param $user Selected user (the one watching promo)
1345 * @param $grade Formation the user is watching
1346 */
4e7bf1e0
FB
1347class UFC_WatchPromo extends UFC_UserRelated
1348{
1349 private $grade;
009b8ab7 1350 public function __construct(PlUser &$user, $grade = UserFilter::GRADE_ING)
4e7bf1e0 1351 {
009b8ab7 1352 parent::__construct($user);
4e7bf1e0
FB
1353 $this->grade = $grade;
1354 }
1355
dcc63ed5 1356 public function buildCondition(PlFilter &$uf)
4e7bf1e0 1357 {
009b8ab7
FB
1358 $promos = $this->user->watchPromos();
1359 if (count($promos) == 0) {
dcc63ed5 1360 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
1361 } else {
1362 $sube = $uf->addEducationFilter(true, $this->grade);
1363 $field = 'pe' . $sube . '.' . UserFilter::promoYear($this->grade);
bde68f05 1364 return XDB::format($field . ' IN {?}', $promos);
009b8ab7 1365 }
4e7bf1e0
FB
1366 }
1367}
8363588b 1368// }}}
4e7bf1e0 1369
8363588b 1370// {{{ class UFC_WatchContact
53eae167
RB
1371/** Filters users watched by selected user
1372 */
009b8ab7 1373class UFC_WatchContact extends UFC_Contact
4e7bf1e0 1374{
dcc63ed5 1375 public function buildCondition(PlFilter &$uf)
4e7bf1e0 1376 {
009b8ab7 1377 if (!$this->user->watchContacts()) {
dcc63ed5 1378 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
1379 }
1380 return parent::buildCondition($uf);
4e7bf1e0
FB
1381 }
1382}
8363588b 1383// }}}
4e7bf1e0 1384
48885bbe
FB
1385// {{{ class UFC_MarketingHash
1386/** Filters users using the hash generated
1387 * to send marketing emails to him.
1388 */
1389class UFC_MarketingHash implements UserFilterCondition
1390{
1391 private $hash;
1392
1393 public function __construct($hash)
1394 {
1395 $this->hash = $hash;
1396 }
1397
1398 public function buildCondition(PlFilter &$uf)
1399 {
1400 $table = $uf->addMarketingHash();
1401 return XDB::format('rm.hash = {?}', $this->hash);
1402 }
1403}
416d4244 1404// }}}
4e7bf1e0 1405
d865c296
FB
1406/******************
1407 * ORDERS
1408 ******************/
1409
8363588b 1410// {{{ class UFO_Promo
5d2e55c7
RB
1411/** Orders users by promotion
1412 * @param $grade Formation whose promotion users should be sorted by (restricts results to users of that formation)
53eae167
RB
1413 * @param $desc Whether sort is descending
1414 */
ccc951d9 1415class UFO_Promo extends PlFilterGroupableOrder
d865c296
FB
1416{
1417 private $grade;
1418
1419 public function __construct($grade = null, $desc = false)
1420 {
009b8ab7 1421 parent::__construct($desc);
d865c296 1422 $this->grade = $grade;
d865c296
FB
1423 }
1424
61f61261 1425 protected function getSortTokens(PlFilter &$uf)
d865c296
FB
1426 {
1427 if (UserFilter::isGrade($this->grade)) {
1428 $sub = $uf->addEducationFilter($this->grade);
1429 return 'pe' . $sub . '.' . UserFilter::promoYear($this->grade);
1430 } else {
1431 $sub = $uf->addDisplayFilter();
1432 return 'pd' . $sub . '.promo';
1433 }
1434 }
1435}
8363588b 1436// }}}
d865c296 1437
8363588b 1438// {{{ class UFO_Name
53eae167 1439/** Sorts users by name
5d2e55c7
RB
1440 * @param $type Type of name on which to sort (firstname...)
1441 * @param $variant Variant of that name to use (marital, ordinary...)
53eae167
RB
1442 * @param $particle Set to true if particles should be included in the sorting order
1443 * @param $desc If sort order should be descending
1444 */
ccc951d9 1445class UFO_Name extends PlFilterOrder
d865c296
FB
1446{
1447 private $type;
1448 private $variant;
1449 private $particle;
1450
1451 public function __construct($type, $variant = null, $particle = false, $desc = false)
1452 {
009b8ab7 1453 parent::__construct($desc);
d865c296
FB
1454 $this->type = $type;
1455 $this->variant = $variant;
1456 $this->particle = $particle;
d865c296
FB
1457 }
1458
61f61261 1459 protected function getSortTokens(PlFilter &$uf)
d865c296 1460 {
913a4e90 1461 if (Profile::isDisplayName($this->type)) {
d865c296 1462 $sub = $uf->addDisplayFilter();
a9ef52c9
RB
1463 $token = 'pd' . $sub . '.' . $this->type;
1464 if ($uf->accountsRequired()) {
1465 $account_token = Profile::getAccountEquivalentName($this->type);
1466 return 'IFNULL(' . $token . ', a.' . $account_token . ')';
1467 } else {
1468 return $token;
1469 }
d865c296
FB
1470 } else {
1471 $sub = $uf->addNameFilter($this->type, $this->variant);
1472 if ($this->particle) {
1473 return 'CONCAT(pn' . $sub . '.particle, \' \', pn' . $sub . '.name)';
1474 } else {
1475 return 'pn' . $sub . '.name';
1476 }
1477 }
1478 }
1479}
8363588b 1480// }}}
d865c296 1481
40585144 1482// {{{ class UFO_Score
ccc951d9 1483class UFO_Score extends PlFilterOrder
40585144 1484{
61f61261 1485 protected function getSortTokens(PlFilter &$uf)
40585144 1486 {
2a93b634
RB
1487 $toks = $uf->getNameTokens();
1488 $scores = array();
488765e3
RB
1489
1490 // If there weren't any sort tokens, we shouldn't sort by score, sort by NULL instead
1491 if (count($toks) == 0) {
1492 return 'NULL';
1493 }
1494
2a93b634
RB
1495 foreach ($toks as $sub => $token) {
1496 $scores[] = XDB::format('SUM(' . $sub . '.score + IF (' . $sub . '.token = {?}, 5, 0) )', $token);
1497 }
1498 return implode(' + ', $scores);
40585144
RB
1499 }
1500}
1501// }}}
1502
8363588b 1503// {{{ class UFO_Registration
53eae167
RB
1504/** Sorts users based on registration date
1505 */
ccc951d9 1506class UFO_Registration extends PlFilterOrder
38c6fe96 1507{
61f61261 1508 protected function getSortTokens(PlFilter &$uf)
38c6fe96 1509 {
6c1e97ae 1510 $uf->requireAccounts();
009b8ab7 1511 return 'a.registration_date';
38c6fe96 1512 }
009b8ab7 1513}
8363588b 1514// }}}
38c6fe96 1515
8363588b 1516// {{{ class UFO_Birthday
53eae167
RB
1517/** Sorts users based on next birthday date
1518 */
ccc951d9 1519class UFO_Birthday extends PlFilterOrder
009b8ab7 1520{
61f61261 1521 protected function getSortTokens(PlFilter &$uf)
38c6fe96 1522 {
6c1e97ae 1523 $uf->requireProfiles();
009b8ab7 1524 return 'p.next_birthday';
38c6fe96
FB
1525 }
1526}
8363588b 1527// }}}
38c6fe96 1528
8363588b 1529// {{{ class UFO_ProfileUpdate
53eae167
RB
1530/** Sorts users based on last profile update
1531 */
ccc951d9 1532class UFO_ProfileUpdate extends PlFilterOrder
009b8ab7 1533{
61f61261 1534 protected function getSortTokens(PlFilter &$uf)
009b8ab7 1535 {
6c1e97ae 1536 $uf->requireProfiles();
009b8ab7
FB
1537 return 'p.last_change';
1538 }
1539}
8363588b 1540// }}}
009b8ab7 1541
8363588b 1542// {{{ class UFO_Death
53eae167
RB
1543/** Sorts users based on death date
1544 */
ccc951d9 1545class UFO_Death extends PlFilterOrder
009b8ab7 1546{
61f61261 1547 protected function getSortTokens(PlFilter &$uf)
009b8ab7 1548 {
6c1e97ae 1549 $uf->requireProfiles();
009b8ab7
FB
1550 return 'p.deathdate';
1551 }
1552}
8363588b 1553// }}}
009b8ab7 1554
6c1e97ae
FB
1555// {{{ class UFO_Uid
1556/** Sorts users based on their uid
1557 */
ccc951d9 1558class UFO_Uid extends PlFilterOrder
6c1e97ae
FB
1559{
1560 protected function getSortTokens(PlFilter &$uf)
1561 {
1562 $uf->requireAccounts();
93b0da52 1563 return '$UID';
6c1e97ae
FB
1564 }
1565}
c752a130 1566// }}}
6c1e97ae
FB
1567
1568// {{{ class UFO_Hruid
1569/** Sorts users based on their hruid
1570 */
ccc951d9 1571class UFO_Hruid extends PlFilterOrder
6c1e97ae
FB
1572{
1573 protected function getSortTokens(PlFilter &$uf)
1574 {
1575 $uf->requireAccounts();
1576 return 'a.hruid';
1577 }
1578}
1579// }}}
1580
1581// {{{ class UFO_Pid
1582/** Sorts users based on their pid
1583 */
ccc951d9 1584class UFO_Pid extends PlFilterOrder
6c1e97ae
FB
1585{
1586 protected function getSortTokens(PlFilter &$uf)
1587 {
1588 $uf->requireProfiles();
93b0da52 1589 return '$PID';
6c1e97ae
FB
1590 }
1591}
c752a130 1592// }}}
6c1e97ae
FB
1593
1594// {{{ class UFO_Hrpid
1595/** Sorts users based on their hrpid
1596 */
ccc951d9 1597class UFO_Hrpid extends PlFilterOrder
6c1e97ae
FB
1598{
1599 protected function getSortTokens(PlFilter &$uf)
1600 {
1601 $uf->requireProfiles();
1602 return 'p.hrpid';
1603 }
1604}
1605// }}}
1606
009b8ab7 1607
d865c296
FB
1608/***********************************
1609 *********************************
1610 USER FILTER CLASS
1611 *********************************
1612 ***********************************/
1613
8363588b 1614// {{{ class UserFilter
2d83cac9
RB
1615/** This class provides a convenient and centralized way of filtering users.
1616 *
1617 * Usage:
1618 * $uf = new UserFilter(new UFC_Blah($x, $y), new UFO_Coin($z, $t));
1619 *
1620 * Resulting UserFilter can be used to:
1621 * - get a list of User objects matching the filter
1622 * - get a list of UIDs matching the filter
1623 * - get the number of users matching the filter
1624 * - check whether a given User matches the filter
1625 * - filter a list of User objects depending on whether they match the filter
1626 *
1627 * Usage for UFC and UFO objects:
1628 * A UserFilter will call all private functions named XXXJoins.
1629 * These functions must return an array containing the list of join
1630 * required by the various UFC and UFO associated to the UserFilter.
1631 * Entries in those returned array are of the following form:
1632 * 'join_tablealias' => array('join_type', 'joined_table', 'join_criter')
1633 * which will be translated into :
1634 * join_type JOIN joined_table AS join_tablealias ON (join_criter)
1635 * in the final query.
1636 *
1637 * In the join_criter text, $ME is replaced with 'join_tablealias', $PID with
913a4e90 1638 * profile.pid, and $UID with accounts.uid.
2d83cac9
RB
1639 *
1640 * For each kind of "JOIN" needed, a function named addXXXFilter() should be defined;
1641 * its parameter will be used to set various private vars of the UserFilter describing
1642 * the required joins ; such a function shall return the "join_tablealias" to use
1643 * when referring to the joined table.
1644 *
1645 * For example, if data from profile_job must be available to filter results,
aab2ffdd 1646 * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and
2d83cac9
RB
1647 * return 'pj', the short name to use when referring to profile_job; when building
1648 * the query, calling the jobJoins function will return an array containing a single
1649 * row:
1650 * 'pj' => array('left', 'profile_job', '$ME.pid = $UID');
1651 *
1652 * The 'register_optional' function can be used to generate unique table aliases when
1653 * the same table has to be joined several times with different aliases.
1654 */
9b8e5fb4 1655class UserFilter extends PlFilter
a087cc8d 1656{
9b8e5fb4 1657 protected $joinMethods = array();
7ca75030 1658
61f61261
RB
1659 protected $joinMetas = array(
1660 '$PID' => 'p.pid',
1661 '$UID' => 'a.uid',
9b8e5fb4 1662 );
d865c296 1663
a087cc8d 1664 private $root;
24e08e33 1665 private $sort = array();
ccc951d9 1666 private $grouper = null;
784745ce 1667 private $query = null;
24e08e33 1668 private $orderby = null;
784745ce 1669
7f26cd69
RB
1670 // Store the current 'search' visibility.
1671 private $profile_visibility = null;
1672
2daf7250
RB
1673 private $lastusercount = null;
1674 private $lastprofilecount = null;
d865c296 1675
24e08e33 1676 public function __construct($cond = null, $sort = null)
5dd9d823 1677 {
06598c13 1678 if (empty($this->joinMethods)) {
d865c296
FB
1679 $class = new ReflectionClass('UserFilter');
1680 foreach ($class->getMethods() as $method) {
1681 $name = $method->getName();
1682 if (substr($name, -5) == 'Joins' && $name != 'buildJoins') {
06598c13 1683 $this->joinMethods[] = $name;
d865c296
FB
1684 }
1685 }
1686 }
5dd9d823 1687 if (!is_null($cond)) {
06598c13 1688 if ($cond instanceof PlFilterCondition) {
5dd9d823
FB
1689 $this->setCondition($cond);
1690 }
1691 }
24e08e33 1692 if (!is_null($sort)) {
ccc951d9 1693 if ($sort instanceof PlFilterOrder) {
24e08e33 1694 $this->addSort($sort);
d865c296
FB
1695 } else if (is_array($sort)) {
1696 foreach ($sort as $s) {
1697 $this->addSort($s);
1698 }
24e08e33
FB
1699 }
1700 }
7f26cd69
RB
1701
1702 // This will set the visibility to the default correct level.
1703 $this->profile_visibility = new ProfileVisibility();
1704 }
1705
1706 public function getVisibilityLevels()
1707 {
1708 return $this->profile_visibility->levels();
1709 }
1710
1711 public function getVisibilityLevel()
1712 {
1713 return $this->profile_visibility->level();
1714 }
1715
1716 public function restrictVisibilityTo($level)
1717 {
1718 $this->profile_visibility->setLevel($level);
1719 }
1720
1721 public function getVisibilityCondition($field)
1722 {
1723 return $field . ' IN ' . XDB::formatArray($this->getVisibilityLevels());
5dd9d823
FB
1724 }
1725
784745ce
FB
1726 private function buildQuery()
1727 {
2a93b634
RB
1728 // The root condition is built first because some orders need info
1729 // available only once all UFC have set their conditions (UFO_Score)
1730 if (is_null($this->query)) {
1731 $where = $this->root->buildCondition($this);
226626ae
FB
1732 $where = str_replace(array_keys($this->joinMetas),
1733 $this->joinMetas,
1734 $where);
2a93b634 1735 }
d865c296
FB
1736 if (is_null($this->orderby)) {
1737 $orders = array();
1738 foreach ($this->sort as $sort) {
1739 $orders = array_merge($orders, $sort->buildSort($this));
1740 }
1741 if (count($orders) == 0) {
1742 $this->orderby = '';
1743 } else {
1744 $this->orderby = 'ORDER BY ' . implode(', ', $orders);
1745 }
226626ae
FB
1746 $this->orderby = str_replace(array_keys($this->joinMetas),
1747 $this->joinMetas,
1748 $this->orderby);
d865c296 1749 }
784745ce 1750 if (is_null($this->query)) {
2a93b634 1751 if ($this->with_accounts) {
b8dcf62d
RB
1752 $from = 'accounts AS a';
1753 } else {
1754 $this->requireProfiles();
1755 $from = 'profiles AS p';
1756 }
f7ea7450 1757 $joins = $this->buildJoins();
b8dcf62d 1758 $this->query = 'FROM ' . $from . '
784745ce
FB
1759 ' . $joins . '
1760 WHERE (' . $where . ')';
1761 }
1762 }
1763
ccc951d9
RB
1764 public function hasGroups()
1765 {
1766 return $this->grouper != null;
1767 }
1768
1769 public function getGroups()
1770 {
1771 return $this->getUIDGroups();
1772 }
1773
1774 public function getUIDGroups()
1775 {
1776 $this->requireAccounts();
1777 $this->buildQuery();
1778 $token = $this->grouper->getGroupToken($this);
1779
1780 $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(a.uid)
1781 ' . $this->query . '
1782 GROUP BY ' . $token,
1783 0);
1784 return $groups;
1785 }
1786
1787 public function getPIDGroups()
1788 {
1789 $this->requireProfiles();
1790 $this->buildQuery();
1791 $token = $this->grouper->getGroupToken($this);
1792
1793 $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(p.pid)
1794 ' . $this->query . '
1795 GROUP BY ' . $token,
1796 0);
1797 return $groups;
1798 }
1799
7ca75030 1800 private function getUIDList($uids = null, PlLimit &$limit)
d865c296 1801 {
b8dcf62d 1802 $this->requireAccounts();
d865c296 1803 $this->buildQuery();
7ca75030 1804 $lim = $limit->getSql();
d865c296 1805 $cond = '';
45b20ca0 1806 if (!empty($uids)) {
bde68f05 1807 $cond = XDB::format(' AND a.uid IN {?}', $uids);
d865c296
FB
1808 }
1809 $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid
1810 ' . $this->query . $cond . '
1811 GROUP BY a.uid
1812 ' . $this->orderby . '
7ca75030 1813 ' . $lim);
2daf7250 1814 $this->lastusercount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
d865c296
FB
1815 return $fetched;
1816 }
1817
043b104b
RB
1818 private function getPIDList($pids = null, PlLimit &$limit)
1819 {
1820 $this->requireProfiles();
1821 $this->buildQuery();
1822 $lim = $limit->getSql();
1823 $cond = '';
1824 if (!is_null($pids)) {
bde68f05 1825 $cond = XDB::format(' AND p.pid IN {?}', $pids);
043b104b
RB
1826 }
1827 $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS p.pid
1828 ' . $this->query . $cond . '
1829 GROUP BY p.pid
1830 ' . $this->orderby . '
1831 ' . $lim);
2daf7250 1832 $this->lastprofilecount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
043b104b
RB
1833 return $fetched;
1834 }
1835
434570c4
FB
1836 private static function defaultLimit($limit) {
1837 if ($limit == null) {
1838 return new PlLimit();
1839 } else {
1840 return $limit;
1841 }
1842 }
1843
a087cc8d
FB
1844 /** Check that the user match the given rule.
1845 */
1846 public function checkUser(PlUser &$user)
1847 {
b8dcf62d 1848 $this->requireAccounts();
784745ce
FB
1849 $this->buildQuery();
1850 $count = (int)XDB::fetchOneCell('SELECT COUNT(*)
1851 ' . $this->query . XDB::format(' AND a.uid = {?}', $user->id()));
1852 return $count == 1;
a087cc8d
FB
1853 }
1854
043b104b
RB
1855 /** Check that the profile match the given rule.
1856 */
1857 public function checkProfile(Profile &$profile)
1858 {
1859 $this->requireProfiles();
1860 $this->buildQuery();
1861 $count = (int)XDB::fetchOneCell('SELECT COUNT(*)
1862 ' . $this->query . XDB::format(' AND p.pid = {?}', $profile->id()));
1863 return $count == 1;
1864 }
1865
1866 /** Default filter is on users
a087cc8d 1867 */
434570c4 1868 public function filter(array $users, $limit = null)
a087cc8d 1869 {
434570c4 1870 return $this->filterUsers($users, self::defaultLimit($limit));
043b104b
RB
1871 }
1872
1873 /** Filter a list of users to extract the users matching the rule.
1874 */
434570c4 1875 public function filterUsers(array $users, $limit = null)
043b104b 1876 {
434570c4 1877 $limit = self::defaultLimit($limit);
b8dcf62d 1878 $this->requireAccounts();
4927ee54
FB
1879 $this->buildQuery();
1880 $table = array();
1881 $uids = array();
1882 foreach ($users as $user) {
07eb5b0e
FB
1883 if ($user instanceof PlUser) {
1884 $uid = $user->id();
1885 } else {
1886 $uid = $user;
1887 }
1888 $uids[] = $uid;
1889 $table[$uid] = $user;
4927ee54 1890 }
7ca75030 1891 $fetched = $this->getUIDList($uids, $limit);
a087cc8d 1892 $output = array();
4927ee54
FB
1893 foreach ($fetched as $uid) {
1894 $output[] = $table[$uid];
a087cc8d
FB
1895 }
1896 return $output;
1897 }
1898
043b104b
RB
1899 /** Filter a list of profiles to extract the users matching the rule.
1900 */
434570c4 1901 public function filterProfiles(array $profiles, $limit = null)
043b104b 1902 {
434570c4 1903 $limit = self::defaultLimit($limit);
043b104b
RB
1904 $this->requireProfiles();
1905 $this->buildQuery();
1906 $table = array();
1907 $pids = array();
1908 foreach ($profiles as $profile) {
1909 if ($profile instanceof Profile) {
1910 $pid = $profile->id();
1911 } else {
1912 $pid = $profile;
1913 }
1914 $pids[] = $pid;
1915 $table[$pid] = $profile;
1916 }
1917 $fetched = $this->getPIDList($pids, $limit);
1918 $output = array();
1919 foreach ($fetched as $pid) {
1920 $output[] = $table[$pid];
1921 }
1922 return $output;
1923 }
1924
434570c4 1925 public function getUIDs($limit = null)
7ca75030 1926 {
833a6e86
FB
1927 $limit = self::defaultLimit($limit);
1928 return $this->getUIDList(null, $limit);
7ca75030
RB
1929 }
1930
ad27b22e
FB
1931 public function getUID($pos = 0)
1932 {
983f3864 1933 $uids =$this->getUIDList(null, new PlLimit(1, $pos));
ad27b22e
FB
1934 if (count($uids) == 0) {
1935 return null;
1936 } else {
1937 return $uids[0];
1938 }
1939 }
1940
434570c4 1941 public function getPIDs($limit = null)
043b104b 1942 {
833a6e86
FB
1943 $limit = self::defaultLimit($limit);
1944 return $this->getPIDList(null, $limit);
043b104b
RB
1945 }
1946
ad27b22e
FB
1947 public function getPID($pos = 0)
1948 {
983f3864 1949 $pids =$this->getPIDList(null, new PlLimit(1, $pos));
ad27b22e
FB
1950 if (count($pids) == 0) {
1951 return null;
1952 } else {
1953 return $pids[0];
1954 }
1955 }
1956
434570c4 1957 public function getUsers($limit = null)
4927ee54 1958 {
7ca75030 1959 return User::getBulkUsersWithUIDs($this->getUIDs($limit));
d865c296
FB
1960 }
1961
ad27b22e
FB
1962 public function getUser($pos = 0)
1963 {
1964 $uid = $this->getUID($pos);
1965 if ($uid == null) {
1966 return null;
1967 } else {
1968 return User::getWithUID($uid);
1969 }
1970 }
1971
0d906109
RB
1972 public function iterUsers($limit = null)
1973 {
1974 return User::iterOverUIDs($this->getUIDs($limit));
1975 }
1976
00f83317 1977 public function getProfiles($limit = null, $fields = 0x0000, $visibility = null)
043b104b 1978 {
00f83317 1979 return Profile::getBulkProfilesWithPIDs($this->getPIDs($limit), $fields, $visibility);
043b104b
RB
1980 }
1981
00f83317 1982 public function getProfile($pos = 0, $fields = 0x0000, $visibility = null)
ad27b22e
FB
1983 {
1984 $pid = $this->getPID($pos);
1985 if ($pid == null) {
1986 return null;
1987 } else {
00f83317 1988 return Profile::get($pid, $fields, $visibility);
ad27b22e
FB
1989 }
1990 }
1991
00f83317 1992 public function iterProfiles($limit = null, $fields = 0x0000, $visibility = null)
0d906109 1993 {
00f83317 1994 return Profile::iterOverPIDs($this->getPIDs($limit), true, $fields, $visibility);
0d906109
RB
1995 }
1996
434570c4 1997 public function get($limit = null)
d865c296 1998 {
7ca75030 1999 return $this->getUsers($limit);
4927ee54
FB
2000 }
2001
aaf70eb8 2002
d865c296 2003 public function getTotalCount()
4927ee54 2004 {
2daf7250
RB
2005 return $this->getTotalUserCount();
2006 }
2007
2008 public function getTotalUserCount()
2009 {
2010 if (is_null($this->lastusercount)) {
2011 $this->requireAccounts();
aa21c568 2012 $this->buildQuery();
2daf7250
RB
2013 return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT a.uid)
2014 ' . $this->query);
2015 } else {
2016 return $this->lastusercount;
2017 }
2018 }
2019
2020 public function getTotalProfileCount()
2021 {
2022 if (is_null($this->lastprofilecount)) {
2023 $this->requireProfiles();
2024 $this->buildQuery();
2025 return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT p.pid)
7e735012 2026 ' . $this->query);
38c6fe96 2027 } else {
2daf7250 2028 return $this->lastprofilecount;
38c6fe96 2029 }
4927ee54
FB
2030 }
2031
9b8e5fb4 2032 public function setCondition(PlFilterCondition &$cond)
a087cc8d
FB
2033 {
2034 $this->root =& $cond;
784745ce 2035 $this->query = null;
a087cc8d
FB
2036 }
2037
9b8e5fb4 2038 public function addSort(PlFilterOrder &$sort)
24e08e33 2039 {
ccc951d9
RB
2040 if (count($this->sort) == 0 && $sort instanceof PlFilterGroupableOrder)
2041 {
2042 $this->grouper = $sort;
2043 }
d865c296
FB
2044 $this->sort[] = $sort;
2045 $this->orderby = null;
24e08e33
FB
2046 }
2047
a087cc8d
FB
2048 static public function getLegacy($promo_min, $promo_max)
2049 {
a087cc8d 2050 if ($promo_min != 0) {
784745ce 2051 $min = new UFC_Promo('>=', self::GRADE_ING, intval($promo_min));
5dd9d823 2052 } else {
88c31faf 2053 $min = new PFC_True();
a087cc8d 2054 }
a087cc8d 2055 if ($promo_max != 0) {
784745ce 2056 $max = new UFC_Promo('<=', self::GRADE_ING, intval($promo_max));
a087cc8d 2057 } else {
88c31faf 2058 $max = new PFC_True();
a087cc8d 2059 }
9b8e5fb4 2060 return new UserFilter(new PFC_And($min, $max));
a087cc8d 2061 }
784745ce 2062
07eb5b0e
FB
2063 static public function sortByName()
2064 {
913a4e90 2065 return array(new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME));
07eb5b0e
FB
2066 }
2067
2068 static public function sortByPromo()
2069 {
913a4e90 2070 return array(new UFO_Promo(), new UFO_Name(Profile::LASTNAME), new UFO_Name(Profile::FIRSTNAME));
07eb5b0e
FB
2071 }
2072
aa21c568
FB
2073 static private function getDBSuffix($string)
2074 {
2d6329a2
FB
2075 if (is_array($string)) {
2076 if (count($string) == 1) {
2077 return self::getDBSuffix(array_pop($string));
2078 }
2079 return md5(implode('|', $string));
2080 } else {
2081 return preg_replace('/[^a-z0-9]/i', '', $string);
2082 }
aa21c568
FB
2083 }
2084
2085
2d83cac9
RB
2086 /** Stores a new (and unique) table alias in the &$table table
2087 * @param &$table Array in which the table alias must be stored
2088 * @param $val Value which will then be used to build the join
2089 * @return Name of the newly created alias
2090 */
aa21c568
FB
2091 private $option = 0;
2092 private function register_optional(array &$table, $val)
2093 {
2094 if (is_null($val)) {
2095 $sub = $this->option++;
2096 $index = null;
2097 } else {
2098 $sub = self::getDBSuffix($val);
2099 $index = $val;
2100 }
2101 $sub = '_' . $sub;
2102 $table[$sub] = $index;
2103 return $sub;
2104 }
784745ce 2105
b8dcf62d
RB
2106 /** PROFILE VS ACCOUNT
2107 */
f7ea7450
RB
2108 private $with_profiles = false;
2109 private $with_accounts = false;
b8dcf62d
RB
2110 public function requireAccounts()
2111 {
2112 $this->with_accounts = true;
2113 }
2114
a9ef52c9
RB
2115 public function accountsRequired()
2116 {
2117 return $this->with_accounts;
2118 }
2119
b8dcf62d
RB
2120 public function requireProfiles()
2121 {
2122 $this->with_profiles = true;
2123 }
2124
a9ef52c9
RB
2125 public function profilesRequired()
2126 {
2127 return $this->with_profiles;
2128 }
2129
b8dcf62d
RB
2130 protected function accountJoins()
2131 {
2132 $joins = array();
2a93b634 2133 if ($this->with_profiles && $this->with_accounts) {
5c412626
FB
2134 $joins['ap'] = PlSqlJoin::left('account_profiles', '$ME.uid = $UID AND FIND_IN_SET(\'owner\', ap.perms)');
2135 $joins['p'] = PlSqlJoin::left('profiles', '$PID = ap.pid');
b8dcf62d
RB
2136 }
2137 return $joins;
2138 }
2139
1eabd2a4
FB
2140 /** PERMISSIONS
2141 */
2142 private $at = false;
2143 public function requirePerms()
2144 {
2145 $this->requireAccounts();
2146 $this->at = true;
2147 return 'at';
2148 }
2149
2150 protected function permJoins()
2151 {
2152 if ($this->at) {
2153 return array('at' => PlSqlJoin::left('account_types', '$ME.type = a.type'));
2154 } else {
2155 return array();
2156 }
2157 }
2158
d865c296
FB
2159 /** DISPLAY
2160 */
38c6fe96 2161 const DISPLAY = 'display';
d865c296
FB
2162 private $pd = false;
2163 public function addDisplayFilter()
2164 {
b8dcf62d 2165 $this->requireProfiles();
d865c296
FB
2166 $this->pd = true;
2167 return '';
2168 }
2169
9b8e5fb4 2170 protected function displayJoins()
d865c296
FB
2171 {
2172 if ($this->pd) {
5c412626 2173 return array('pd' => PlSqlJoin::left('profile_display', '$ME.pid = $PID'));
d865c296
FB
2174 } else {
2175 return array();
2176 }
2177 }
2178
f73a4f1b
RB
2179 /** LOGGER
2180 */
2181
2182 private $with_logger = false;
2183 public function addLoggerFilter()
2184 {
2185 $this->with_logger = true;
2186 $this->requireAccounts();
2187 return 'ls';
2188 }
2189 protected function loggerJoins()
2190 {
2191 $joins = array();
2192 if ($this->with_logger) {
5c412626 2193 $joins['ls'] = PlSqlJoin::left('log_sessions', '$ME.uid = $UID');
f73a4f1b
RB
2194 }
2195 return $joins;
2196 }
2197
784745ce
FB
2198 /** NAMES
2199 */
784745ce
FB
2200
2201 static public function assertName($name)
2202 {
07613cdd 2203 if (!DirEnum::getID(DirEnum::NAMETYPES, $name)) {
9b8e5fb4 2204 Platal::page()->kill('Invalid name type: ' . $name);
784745ce
FB
2205 }
2206 }
2207
2208 private $pn = array();
784745ce
FB
2209 public function addNameFilter($type, $variant = null)
2210 {
b8dcf62d 2211 $this->requireProfiles();
784745ce
FB
2212 if (!is_null($variant)) {
2213 $ft = $type . '_' . $variant;
2214 } else {
2215 $ft = $type;
2216 }
2217 $sub = '_' . $ft;
2218 self::assertName($ft);
2219
2220 if (!is_null($variant) && $variant == 'other') {
aa21c568 2221 $sub .= $this->option++;
784745ce 2222 }
07613cdd 2223 $this->pn[$sub] = DirEnum::getID(DirEnum::NAMETYPES, $ft);
784745ce
FB
2224 return $sub;
2225 }
2226
9b8e5fb4 2227 protected function nameJoins()
784745ce
FB
2228 {
2229 $joins = array();
2230 foreach ($this->pn as $sub => $type) {
5c412626 2231 $joins['pn' . $sub] = PlSqlJoin::left('profile_name', '$ME.pid = $PID AND $ME.typeid = {?}', $type);
784745ce
FB
2232 }
2233 return $joins;
2234 }
2235
40585144
RB
2236 /** NAMETOKENS
2237 */
2a93b634
RB
2238 private $name_tokens = array();
2239 private $nb_tokens = 0;
2240
2241 public function addNameTokensFilter($token)
40585144
RB
2242 {
2243 $this->requireProfiles();
2a93b634
RB
2244 $sub = 'sn' . (1 + $this->nb_tokens);
2245 $this->nb_tokens++;
2246 $this->name_tokens[$sub] = $token;
2247 return $sub;
40585144
RB
2248 }
2249
2250 protected function nameTokensJoins()
2251 {
f7ea7450 2252 /* We don't return joins, since with_sn forces the SELECT to run on search_name first */
2a93b634
RB
2253 $joins = array();
2254 foreach ($this->name_tokens as $sub => $token) {
2255 $joins[$sub] = PlSqlJoin::left('search_name', '$ME.pid = $PID');
40585144 2256 }
2a93b634
RB
2257 return $joins;
2258 }
2259
2260 public function getNameTokens()
2261 {
2262 return $this->name_tokens;
40585144
RB
2263 }
2264
a7f8e48a
RB
2265 /** NATIONALITY
2266 */
2267
2268 private $with_nat = false;
2269 public function addNationalityFilter()
2270 {
2271 $this->with_nat = true;
2272 return 'ngc';
2273 }
2274
2275 protected function nationalityJoins()
2276 {
2277 $joins = array();
2278 if ($this->with_nat) {
5c412626 2279 $joins['ngc'] = PlSqlJoin::left('geoloc_countries', '$ME.iso_3166_1_a2 = p.nationality1 OR $ME.iso_3166_1_a2 = p.nationality2 OR $ME.iso_3166_1_a2 = p.nationality3');
a7f8e48a
RB
2280 }
2281 return $joins;
2282 }
2283
784745ce
FB
2284 /** EDUCATION
2285 */
2286 const GRADE_ING = 'Ing.';
2287 const GRADE_PHD = 'PhD';
2288 const GRADE_MST = 'M%';
2289 static public function isGrade($grade)
2290 {
93c2f133 2291 return ($grade !== 0) && ($grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST);
784745ce
FB
2292 }
2293
2294 static public function assertGrade($grade)
2295 {
2296 if (!self::isGrade($grade)) {
ad27b22e 2297 Platal::page()->killError("Diplôme non valide: $grade");
784745ce
FB
2298 }
2299 }
2300
d865c296
FB
2301 static public function promoYear($grade)
2302 {
2303 // XXX: Definition of promotion for phds and masters might change in near future.
2304 return ($grade == UserFilter::GRADE_ING) ? 'entry_year' : 'grad_year';
2305 }
2306
784745ce
FB
2307 private $pepe = array();
2308 private $with_pee = false;
784745ce
FB
2309 public function addEducationFilter($x = false, $grade = null)
2310 {
b8dcf62d 2311 $this->requireProfiles();
784745ce 2312 if (!$x) {
aa21c568
FB
2313 $index = $this->option;
2314 $sub = $this->option++;
784745ce
FB
2315 } else {
2316 self::assertGrade($grade);
2317 $index = $grade;
2318 $sub = $grade[0];
2319 $this->with_pee = true;
2320 }
2321 $sub = '_' . $sub;
2322 $this->pepe[$index] = $sub;
2323 return $sub;
2324 }
2325
9b8e5fb4 2326 protected function educationJoins()
784745ce
FB
2327 {
2328 $joins = array();
2329 if ($this->with_pee) {
5c412626 2330 $joins['pee'] = PlSqlJoin::inner('profile_education_enum', 'pee.abbreviation = \'X\'');
784745ce
FB
2331 }
2332 foreach ($this->pepe as $grade => $sub) {
2333 if ($this->isGrade($grade)) {
5c412626
FB
2334 $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.eduid = pee.id AND $ME.pid = $PID');
2335 $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid AND $ME.abbreviation LIKE {?}', $grade);
784745ce 2336 } else {
5c412626
FB
2337 $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.pid = $PID');
2338 $joins['pee' . $sub] = PlSqlJoin::inner('profile_education_enum', '$ME.id = pe' . $sub . '.eduid');
2339 $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid');
784745ce
FB
2340 }
2341 }
2342 return $joins;
2343 }
4927ee54
FB
2344
2345
2346 /** GROUPS
2347 */
2348 private $gpm = array();
4927ee54
FB
2349 public function addGroupFilter($group = null)
2350 {
b8dcf62d 2351 $this->requireAccounts();
4927ee54 2352 if (!is_null($group)) {
4aae4d2c 2353 if (is_int($group) || ctype_digit($group)) {
4927ee54
FB
2354 $index = $sub = $group;
2355 } else {
2356 $index = $group;
aa21c568 2357 $sub = self::getDBSuffix($group);
4927ee54
FB
2358 }
2359 } else {
aa21c568 2360 $sub = 'group_' . $this->option++;
4927ee54
FB
2361 $index = null;
2362 }
2363 $sub = '_' . $sub;
2364 $this->gpm[$sub] = $index;
2365 return $sub;
2366 }
2367
9b8e5fb4 2368 protected function groupJoins()
4927ee54
FB
2369 {
2370 $joins = array();
2371 foreach ($this->gpm as $sub => $key) {
2372 if (is_null($key)) {
5c412626
FB
2373 $joins['gpa' . $sub] = PlSqlJoin::inner('groups');
2374 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4aae4d2c 2375 } else if (is_int($key) || ctype_digit($key)) {
5c412626 2376 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = ' . $key);
4927ee54 2377 } else {
5c412626
FB
2378 $joins['gpa' . $sub] = PlSqlJoin::inner('groups', '$ME.diminutif = {?}', $key);
2379 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4927ee54
FB
2380 }
2381 }
2382 return $joins;
0fb3713c
RB
2383 }
2384
2385 /** BINETS
2386 */
2387
a7f8e48a
RB
2388 private $with_bi = false;
2389 private $with_bd = false;
d7ddf29b 2390 public function addBinetsFilter($with_enum = false)
0fb3713c
RB
2391 {
2392 $this->requireProfiles();
a7f8e48a
RB
2393 $this->with_bi = true;
2394 if ($with_enum) {
2395 $this->with_bd = true;
2396 return 'bd';
2397 } else {
2398 return 'bi';
2399 }
0fb3713c
RB
2400 }
2401
2402 protected function binetsJoins()
2403 {
2404 $joins = array();
a7f8e48a 2405 if ($this->with_bi) {
5c412626 2406 $joins['bi'] = PlSqlJoin::left('profile_binets', '$ME.pid = $PID');
0fb3713c 2407 }
a7f8e48a 2408 if ($this->with_bd) {
5c412626 2409 $joins['bd'] = PlSqlJoin::left('profile_binet_enum', '$ME.id = bi.binet_id');
a7f8e48a 2410 }
0fb3713c 2411 return $joins;
4927ee54 2412 }
aa21c568
FB
2413
2414 /** EMAILS
2415 */
2416 private $e = array();
2417 public function addEmailRedirectFilter($email = null)
2418 {
b8dcf62d 2419 $this->requireAccounts();
aa21c568
FB
2420 return $this->register_optional($this->e, $email);
2421 }
2422
2423 private $ve = array();
2424 public function addVirtualEmailFilter($email = null)
2425 {
21401768 2426 $this->addAliasFilter(self::ALIAS_FORLIFE);
aa21c568
FB
2427 return $this->register_optional($this->ve, $email);
2428 }
2429
21401768
FB
2430 const ALIAS_BEST = 'bestalias';
2431 const ALIAS_FORLIFE = 'forlife';
aa21c568
FB
2432 private $al = array();
2433 public function addAliasFilter($alias = null)
2434 {
b8dcf62d 2435 $this->requireAccounts();
aa21c568
FB
2436 return $this->register_optional($this->al, $alias);
2437 }
2438
9b8e5fb4 2439 protected function emailJoins()
aa21c568
FB
2440 {
2441 global $globals;
2442 $joins = array();
2443 foreach ($this->e as $sub=>$key) {
2444 if (is_null($key)) {
5c412626 2445 $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\'');
aa21c568 2446 } else {
2d6329a2
FB
2447 if (!is_array($key)) {
2448 $key = array($key);
2449 }
aab2ffdd 2450 $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\'
2f1c94e0 2451 AND $ME.email IN {?}', $key);
aa21c568
FB
2452 }
2453 }
21401768 2454 foreach ($this->al as $sub=>$key) {
aa21c568 2455 if (is_null($key)) {
5c412626 2456 $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\')');
21401768 2457 } else if ($key == self::ALIAS_BEST) {
5c412626 2458 $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND FIND_IN_SET(\'bestalias\', $ME.flags)');
21401768 2459 } else if ($key == self::ALIAS_FORLIFE) {
5c412626 2460 $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type = \'a_vie\'');
aa21c568 2461 } else {
2d6329a2
FB
2462 if (!is_array($key)) {
2463 $key = array($key);
2464 }
aab2ffdd 2465 $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\')
bde68f05 2466 AND $ME.alias IN {?}', $key);
aa21c568 2467 }
aa21c568 2468 }
21401768 2469 foreach ($this->ve as $sub=>$key) {
aa21c568 2470 if (is_null($key)) {
5c412626 2471 $joins['v' . $sub] = PlSqlJoin::left('virtual', '$ME.type = \'user\'');
aa21c568 2472 } else {
2d6329a2
FB
2473 if (!is_array($key)) {
2474 $key = array($key);
2475 }
bde68f05 2476 $joins['v' . $sub] = PlSqlJoin::left('virtual', '$ME.type = \'user\' AND $ME.alias IN {?}', $key);
aa21c568 2477 }
5c412626
FB
2478 $joins['vr' . $sub] = PlSqlJoin::left('virtual_redirect',
2479 '$ME.vid = v' . $sub . '.vid
2480 AND ($ME.redirect IN (CONCAT(al_forlife.alias, \'@\', {?}),
2481 CONCAT(al_forlife.alias, \'@\', {?}),
2482 a.email))',
2483 $globals->mail->domain, $globals->mail->domain2);
aa21c568
FB
2484 }
2485 return $joins;
2486 }
3f42a6ad
FB
2487
2488
c4b24511
RB
2489 /** ADDRESSES
2490 */
036d1637 2491 private $with_pa = false;
c4b24511
RB
2492 public function addAddressFilter()
2493 {
b8dcf62d 2494 $this->requireProfiles();
036d1637
RB
2495 $this->with_pa = true;
2496 return 'pa';
c4b24511
RB
2497 }
2498
2b9ca54d
RB
2499 private $with_pac = false;
2500 public function addAddressCountryFilter()
2501 {
2502 $this->requireProfiles();
2503 $this->addAddressFilter();
2504 $this->with_pac = true;
2505 return 'gc';
2506 }
2507
d7ddf29b 2508 private $with_pal = false;
2b9ca54d
RB
2509 public function addAddressLocalityFilter()
2510 {
2511 $this->requireProfiles();
2512 $this->addAddressFilter();
2513 $this->with_pal = true;
2514 return 'gl';
2515 }
2516
9b8e5fb4 2517 protected function addressJoins()
c4b24511
RB
2518 {
2519 $joins = array();
036d1637 2520 if ($this->with_pa) {
5c412626 2521 $joins['pa'] = PlSqlJoin::left('profile_addresses', '$ME.pid = $PID');
c4b24511 2522 }
2b9ca54d 2523 if ($this->with_pac) {
5c412626 2524 $joins['gc'] = PlSqlJoin::left('geoloc_countries', '$ME.iso_3166_1_a2 = pa.countryID');
2b9ca54d
RB
2525 }
2526 if ($this->with_pal) {
5c412626 2527 $joins['gl'] = PlSqlJoin::left('geoloc_localities', '$ME.id = pa.localityID');
2b9ca54d 2528 }
c4b24511
RB
2529 return $joins;
2530 }
2531
2532
4083b126
RB
2533 /** CORPS
2534 */
2535
2536 private $pc = false;
2537 private $pce = array();
2538 private $pcr = false;
2539 public function addCorpsFilter($type)
2540 {
b8dcf62d 2541 $this->requireProfiles();
4083b126
RB
2542 $this->pc = true;
2543 if ($type == UFC_Corps::CURRENT) {
2544 $pce['pcec'] = 'current_corpsid';
2545 return 'pcec';
2546 } else if ($type == UFC_Corps::ORIGIN) {
2547 $pce['pceo'] = 'original_corpsid';
2548 return 'pceo';
2549 }
2550 }
2551
2552 public function addCorpsRankFilter()
2553 {
b8dcf62d 2554 $this->requireProfiles();
4083b126
RB
2555 $this->pc = true;
2556 $this->pcr = true;
2557 return 'pcr';
2558 }
2559
9b8e5fb4 2560 protected function corpsJoins()
4083b126
RB
2561 {
2562 $joins = array();
2563 if ($this->pc) {
5c412626 2564 $joins['pc'] = PlSqlJoin::left('profile_corps', '$ME.pid = $PID');
4083b126
RB
2565 }
2566 if ($this->pcr) {
5c412626 2567 $joins['pcr'] = PlSqlJoin::left('profile_corps_rank_enum', '$ME.id = pc.rankid');
4083b126
RB
2568 }
2569 foreach($this->pce as $sub => $field) {
5c412626 2570 $joins[$sub] = PlSqlJoin::left('profile_corps_enum', '$ME.id = pc.' . $field);
4083b126
RB
2571 }
2572 return $joins;
2573 }
2574
6a99c3ac
RB
2575 /** JOBS
2576 */
2577
da40b2a4
SJ
2578 const JOB_USERDEFINED = 0x0001;
2579 const JOB_CV = 0x0002;
2580 const JOB_ANY = 0x0003;
6a99c3ac
RB
2581
2582 /** Joins :
2583 * pj => profile_job
2584 * pje => profile_job_enum
3ac45f10 2585 * pjt => profile_job_terms
6a99c3ac 2586 */
da40b2a4 2587 private $with_pj = false;
6a99c3ac 2588 private $with_pje = false;
3ac45f10 2589 private $with_pjt = 0;
6a99c3ac
RB
2590
2591 public function addJobFilter()
2592 {
b8dcf62d 2593 $this->requireProfiles();
6a99c3ac
RB
2594 $this->with_pj = true;
2595 return 'pj';
2596 }
2597
2598 public function addJobCompanyFilter()
2599 {
2600 $this->addJobFilter();
2601 $this->with_pje = true;
2602 return 'pje';
2603 }
2604
3ac45f10
PC
2605 /**
2606 * Adds a filter on job terms of profile.
2607 * @param $nb the number of job terms to use
2608 * @return an array of the fields to filter (one for each term).
3ac45f10
PC
2609 */
2610 public function addJobTermsFilter($nb = 1)
2611 {
2612 $this->with_pjt = $nb;
2613 $jobtermstable = array();
2614 for ($i = 1; $i <= $nb; ++$i) {
4ec03752 2615 $jobtermstable[] = 'pjtr_'.$i;
3ac45f10
PC
2616 }
2617 return $jobtermstable;
2618 }
2619
9b8e5fb4 2620 protected function jobJoins()
6a99c3ac
RB
2621 {
2622 $joins = array();
2623 if ($this->with_pj) {
5c412626 2624 $joins['pj'] = PlSqlJoin::left('profile_job', '$ME.pid = $PID');
6a99c3ac
RB
2625 }
2626 if ($this->with_pje) {
5c412626 2627 $joins['pje'] = PlSqlJoin::left('profile_job_enum', '$ME.id = pj.jobid');
6a99c3ac 2628 }
3ac45f10
PC
2629 if ($this->with_pjt > 0) {
2630 for ($i = 1; $i <= $this->with_pjt; ++$i) {
2631 $joins['pjt_'.$i] = PlSqlJoin::left('profile_job_term', '$ME.pid = $PID');
2632 $joins['pjtr_'.$i] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pjt_'.$i.'.jtid');
2633 }
2634 }
6a99c3ac
RB
2635 return $joins;
2636 }
2637
0a2e9c74
RB
2638 /** NETWORKING
2639 */
2640
2641 private $with_pnw = false;
2642 public function addNetworkingFilter()
2643 {
b8dcf62d 2644 $this->requireAccounts();
0a2e9c74
RB
2645 $this->with_pnw = true;
2646 return 'pnw';
2647 }
2648
9b8e5fb4 2649 protected function networkingJoins()
0a2e9c74
RB
2650 {
2651 $joins = array();
2652 if ($this->with_pnw) {
5c412626 2653 $joins['pnw'] = PlSqlJoin::left('profile_networking', '$ME.pid = $PID');
0a2e9c74
RB
2654 }
2655 return $joins;
2656 }
2657
6d62969e
RB
2658 /** PHONE
2659 */
2660
2d83cac9 2661 private $with_ptel = false;
6d62969e
RB
2662
2663 public function addPhoneFilter()
2664 {
b8dcf62d 2665 $this->requireAccounts();
2d83cac9 2666 $this->with_ptel = true;
6d62969e
RB
2667 return 'ptel';
2668 }
2669
9b8e5fb4 2670 protected function phoneJoins()
6d62969e
RB
2671 {
2672 $joins = array();
2d83cac9 2673 if ($this->with_ptel) {
5c412626 2674 $joins['ptel'] = PlSqlJoin::left('profile_phones', '$ME.pid = $PID');
6d62969e
RB
2675 }
2676 return $joins;
2677 }
2678
ceb512d2
RB
2679 /** MEDALS
2680 */
2681
2d83cac9 2682 private $with_pmed = false;
ceb512d2
RB
2683 public function addMedalFilter()
2684 {
b8dcf62d 2685 $this->requireProfiles();
2d83cac9 2686 $this->with_pmed = true;
ceb512d2
RB
2687 return 'pmed';
2688 }
2689
9b8e5fb4 2690 protected function medalJoins()
ceb512d2
RB
2691 {
2692 $joins = array();
2d83cac9 2693 if ($this->with_pmed) {
5c412626 2694 $joins['pmed'] = PlSqlJoin::left('profile_medals', '$ME.pid = $PID');
ceb512d2
RB
2695 }
2696 return $joins;
2697 }
2698
671b7073
RB
2699 /** MENTORING
2700 */
2701
2702 private $pms = array();
459e6f81 2703 private $mjtr = false;
96f01fba
RB
2704 const MENTOR = 1;
2705 const MENTOR_EXPERTISE = 2;
2706 const MENTOR_COUNTRY = 3;
da40b2a4 2707 const MENTOR_TERM = 4;
671b7073
RB
2708
2709 public function addMentorFilter($type)
2710 {
b8dcf62d 2711 $this->requireAccounts();
671b7073 2712 switch($type) {
96f01fba
RB
2713 case self::MENTOR:
2714 $this->pms['pm'] = 'profile_mentor';
2715 return 'pm';
4a93c3a3
RB
2716 case self::MENTOR_EXPERTISE:
2717 $this->pms['pme'] = 'profile_mentor';
671b7073 2718 return 'pme';
4a93c3a3
RB
2719 case self::MENTOR_COUNTRY:
2720 $this->pms['pmc'] = 'profile_mentor_country';
671b7073 2721 return 'pmc';
459e6f81
PC
2722 case self::MENTOR_TERM:
2723 $this->pms['pmt'] = 'profile_mentor_term';
2724 $this->mjtr = true;
2725 return 'mjtr';
671b7073 2726 default:
5d2e55c7 2727 Platal::page()->killError("Undefined mentor filter.");
671b7073
RB
2728 }
2729 }
2730
9b8e5fb4 2731 protected function mentorJoins()
671b7073
RB
2732 {
2733 $joins = array();
2734 foreach ($this->pms as $sub => $tab) {
5c412626 2735 $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID');
671b7073 2736 }
459e6f81
PC
2737 if ($this->mjtr) {
2738 $joins['mjtr'] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pmt.jtid');
2739 }
671b7073
RB
2740 return $joins;
2741 }
2742
3f42a6ad
FB
2743 /** CONTACTS
2744 */
2745 private $cts = array();
2746 public function addContactFilter($uid = null)
2747 {
c96da6c1 2748 $this->requireProfiles();
3f42a6ad
FB
2749 return $this->register_optional($this->cts, is_null($uid) ? null : 'user_' . $uid);
2750 }
2751
9b8e5fb4 2752 protected function contactJoins()
3f42a6ad
FB
2753 {
2754 $joins = array();
2755 foreach ($this->cts as $sub=>$key) {
2756 if (is_null($key)) {
5c412626 2757 $joins['c' . $sub] = PlSqlJoin::left('contacts', '$ME.contact = $PID');
3f42a6ad 2758 } else {
5c412626 2759 $joins['c' . $sub] = PlSqlJoin::left('contacts', '$ME.uid = {?} AND $ME.contact = $PID', substr($key, 5));
3f42a6ad
FB
2760 }
2761 }
2762 return $joins;
2763 }
4e7bf1e0
FB
2764
2765
2766 /** CARNET
2767 */
2768 private $wn = array();
2769 public function addWatchRegistrationFilter($uid = null)
2770 {
b8dcf62d 2771 $this->requireAccounts();
4e7bf1e0
FB
2772 return $this->register_optional($this->wn, is_null($uid) ? null : 'user_' . $uid);
2773 }
2774
2775 private $wp = array();
2776 public function addWatchPromoFilter($uid = null)
2777 {
b8dcf62d 2778 $this->requireAccounts();
4e7bf1e0
FB
2779 return $this->register_optional($this->wp, is_null($uid) ? null : 'user_' . $uid);
2780 }
2781
2782 private $w = array();
2783 public function addWatchFilter($uid = null)
2784 {
b8dcf62d 2785 $this->requireAccounts();
4e7bf1e0
FB
2786 return $this->register_optional($this->w, is_null($uid) ? null : 'user_' . $uid);
2787 }
2788
9b8e5fb4 2789 protected function watchJoins()
4e7bf1e0
FB
2790 {
2791 $joins = array();
2792 foreach ($this->w as $sub=>$key) {
2793 if (is_null($key)) {
5c412626 2794 $joins['w' . $sub] = PlSqlJoin::left('watch');
4e7bf1e0 2795 } else {
5c412626 2796 $joins['w' . $sub] = PlSqlJoin::left('watch', '$ME.uid = {?}', substr($key, 5));
4e7bf1e0
FB
2797 }
2798 }
2799 foreach ($this->wn as $sub=>$key) {
2800 if (is_null($key)) {
5c412626 2801 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 2802 } else {
5c412626 2803 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5));
4e7bf1e0
FB
2804 }
2805 }
2806 foreach ($this->wn as $sub=>$key) {
2807 if (is_null($key)) {
5c412626 2808 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 2809 } else {
5c412626 2810 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5));
4e7bf1e0
FB
2811 }
2812 }
2813 foreach ($this->wp as $sub=>$key) {
2814 if (is_null($key)) {
5c412626 2815 $joins['wp' . $sub] = PlSqlJoin::left('watch_promo');
4e7bf1e0 2816 } else {
5c412626 2817 $joins['wp' . $sub] = PlSqlJoin::left('watch_promo', '$ME.uid = {?}', substr($key, 5));
4e7bf1e0
FB
2818 }
2819 }
2820 return $joins;
2821 }
48885bbe
FB
2822
2823
470d14f6
FB
2824 /** PHOTOS
2825 */
2826 private $with_photo;
2827 public function addPhotoFilter()
2828 {
2829 $this->requireProfiles();
2830 $this->with_photo = true;
7f26cd69 2831 return 'photo';
470d14f6
FB
2832 }
2833
2834 protected function photoJoins()
2835 {
2836 if ($this->with_photo) {
2837 return array('photo' => PlSqlJoin::left('profile_photos', '$ME.pid = $PID'));
2838 } else {
2839 return array();
2840 }
2841 }
2842
2843
48885bbe
FB
2844 /** MARKETING
2845 */
2846 private $with_rm;
2847 public function addMarketingHash()
2848 {
2849 $this->requireAccounts();
2850 $this->with_rm = true;
2851 }
2852
2853 protected function marketingJoins()
2854 {
2855 if ($this->with_rm) {
5c412626 2856 return array('rm' => PlSqlJoin::left('register_marketing', '$ME.uid = $UID'));
48885bbe
FB
2857 } else {
2858 return array();
2859 }
2860 }
a087cc8d 2861}
8363588b 2862// }}}
3f42a6ad 2863
a7d9ab89
RB
2864// {{{ class ProfileFilter
2865class ProfileFilter extends UserFilter
2866{
434570c4 2867 public function get($limit = null)
a7d9ab89
RB
2868 {
2869 return $this->getProfiles($limit);
2870 }
2daf7250
RB
2871
2872 public function filter(array $profiles, $limit = null)
2873 {
2874 return $this->filterProfiles($profiles, self::defaultLimit($limit));
2875 }
2876
2877 public function getTotalCount()
2878 {
2879 return $this->getTotalProfileCount();
2880 }
ccc951d9
RB
2881
2882 public function getGroups()
2883 {
2884 return $this->getPIDGroups();
2885 }
a7d9ab89
RB
2886}
2887// }}}
2888
a087cc8d
FB
2889// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
2890?>