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