Don't load a User when showing a minifiche, unless necessary
[platal.git] / classes / userfilter.php
CommitLineData
a087cc8d
FB
1<?php
2/***************************************************************************
3 * Copyright (C) 2003-2009 Polytechnique.org *
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
8363588b 42// {{{ class UFC_Profile
53eae167
RB
43/** Filters users who have a profile
44 */
eb1449b8
FB
45class UFC_Profile implements UserFilterCondition
46{
dcc63ed5 47 public function buildCondition(PlFilter &$uf)
eb1449b8
FB
48 {
49 return '$PID IS NOT NULL';
50 }
51}
8363588b 52// }}}
eb1449b8 53
8363588b 54// {{{ class UFC_Promo
5d2e55c7 55/** Filters users based on promotion
53eae167
RB
56 * @param $comparison Comparison operator (>, =, ...)
57 * @param $grade Formation on which to restrict, UserFilter::DISPLAY for "any formation"
5d2e55c7 58 * @param $promo Promotion on which the filter is based
53eae167 59 */
a087cc8d
FB
60class UFC_Promo implements UserFilterCondition
61{
a087cc8d
FB
62
63 private $grade;
64 private $promo;
65 private $comparison;
66
67 public function __construct($comparison, $grade, $promo)
68 {
69 $this->grade = $grade;
70 $this->comparison = $comparison;
71 $this->promo = $promo;
38c6fe96
FB
72 if ($this->grade != UserFilter::DISPLAY) {
73 UserFilter::assertGrade($this->grade);
74 }
a087cc8d
FB
75 }
76
dcc63ed5 77 public function buildCondition(PlFilter &$uf)
a087cc8d 78 {
38c6fe96
FB
79 if ($this->grade == UserFilter::DISPLAY) {
80 $sub = $uf->addDisplayFilter();
1a23a02b 81 return XDB::format('pd' . $sub . '.promo ' . $this->comparison . ' {?}', $this->promo);
38c6fe96
FB
82 } else {
83 $sub = $uf->addEducationFilter(true, $this->grade);
84 $field = 'pe' . $sub . '.' . UserFilter::promoYear($this->grade);
85 return $field . ' IS NOT NULL AND ' . $field . ' ' . $this->comparison . ' ' . XDB::format('{?}', $this->promo);
86 }
784745ce
FB
87 }
88}
8363588b 89// }}}
784745ce 90
8363588b 91// {{{ class UFC_Name
53eae167 92/** Filters users based on name
5d2e55c7 93 * @param $type Type of name field on which filtering is done (firstname, lastname...)
53eae167 94 * @param $text Text on which to filter
5d2e55c7 95 * @param $mode Flag indicating search type (prefix, suffix, with particule...)
53eae167 96 */
784745ce
FB
97class UFC_Name implements UserFilterCondition
98{
99 const PREFIX = 1;
100 const SUFFIX = 2;
101 const PARTICLE = 7;
102 const VARIANTS = 8;
103 const CONTAINS = 3;
104
105 private $type;
106 private $text;
107 private $mode;
108
109 public function __construct($type, $text, $mode)
110 {
111 $this->type = $type;
112 $this->text = $text;
113 $this->mode = $mode;
114 }
115
116 private function buildNameQuery($type, $variant, $where, UserFilter &$uf)
117 {
118 $sub = $uf->addNameFilter($type, $variant);
119 return str_replace('$ME', 'pn' . $sub, $where);
120 }
121
dcc63ed5 122 public function buildCondition(PlFilter &$uf)
784745ce
FB
123 {
124 $left = '$ME.name';
125 $op = ' LIKE ';
126 if (($this->mode & self::PARTICLE) == self::PARTICLE) {
127 $left = 'CONCAT($ME.particle, \' \', $ME.name)';
128 }
129 if (($this->mode & self::CONTAINS) == 0) {
130 $right = XDB::format('{?}', $this->text);
131 $op = ' = ';
132 } else if (($this->mode & self::CONTAINS) == self::PREFIX) {
133 $right = XDB::format('CONCAT({?}, \'%\')', $this->text);
134 } else if (($this->mode & self::CONTAINS) == self::SUFFIX) {
135 $right = XDB::format('CONCAT(\'%\', {?})', $this->text);
136 } else {
137 $right = XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->text);
138 }
139 $cond = $left . $op . $right;
140 $conds = array($this->buildNameQuery($this->type, null, $cond, $uf));
d865c296 141 if (($this->mode & self::VARIANTS) != 0 && isset(UserFilter::$name_variants[$this->type])) {
784745ce
FB
142 foreach (UserFilter::$name_variants[$this->type] as $var) {
143 $conds[] = $this->buildNameQuery($this->type, $var, $cond, $uf);
144 }
145 }
146 return implode(' OR ', $conds);
a087cc8d
FB
147 }
148}
8363588b 149// }}}
a087cc8d 150
40585144
RB
151// {{{ class UFC_NameTokens
152/** Selects users based on tokens in their name (for quicksearch)
153 * @param $tokens An array of tokens to search
154 * @param $flags Flags the tokens must have (e.g 'public' for public search)
155 * @param $soundex (bool) Whether those tokens are fulltext or soundex
156 */
157class UFC_NameTokens implements UserFilterCondition
158{
159 /* Flags */
160 const FLAG_PUBLIC = 'public';
161
162 private $tokens;
163 private $flags;
164 private $soundex;
79a0b464 165 private $exact;
40585144 166
79a0b464 167 public function __construct($tokens, $flags = array(), $soundex = false, $exact = false)
40585144
RB
168 {
169 $this->tokens = $tokens;
170 if (is_array($flags)) {
171 $this->flags = $flags;
172 } else {
173 $this->flags = array($flags);
174 }
175 $this->soundex = $soundex;
79a0b464 176 $this->exact = $exact;
40585144
RB
177 }
178
dcc63ed5 179 public function buildCondition(PlFilter &$uf)
40585144 180 {
79a0b464 181 $sub = $uf->addNameTokensFilter(!($this->exact || $this->soundex));
40585144
RB
182 $conds = array();
183 if ($this->soundex) {
184 $conds[] = $sub . '.soundex IN ' . XDB::formatArray($this->tokens);
79a0b464
RB
185 } else if ($this->exact) {
186 $conds[] = $sub . '.token IN ' . XDB::formatArray($this->tokens);
40585144
RB
187 } else {
188 $tokconds = array();
189 foreach ($this->tokens as $token) {
190 $tokconds[] = $sub . '.token LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $token);
191 }
192 $conds[] = implode(' OR ', $tokconds);
193 }
194
195 if ($this->flags != null) {
196 $conds[] = $sub . '.flags IN ' . XDB::formatArray($this->flags);
197 }
198
199 return implode(' AND ', $conds);
200 }
201}
202// }}}
203
8363588b 204// {{{ class UFC_Dead
53eae167
RB
205/** Filters users based on death date
206 * @param $comparison Comparison operator
207 * @param $date Date to which death date should be compared
208 */
4927ee54
FB
209class UFC_Dead implements UserFilterCondition
210{
38c6fe96
FB
211 private $comparison;
212 private $date;
213
214 public function __construct($comparison = null, $date = null)
4927ee54 215 {
38c6fe96
FB
216 $this->comparison = $comparison;
217 $this->date = $date;
4927ee54
FB
218 }
219
dcc63ed5 220 public function buildCondition(PlFilter &$uf)
4927ee54 221 {
38c6fe96
FB
222 $str = 'p.deathdate IS NOT NULL';
223 if (!is_null($this->comparison)) {
224 $str .= ' AND p.deathdate ' . $this->comparison . ' ' . XDB::format('{?}', date('Y-m-d', $this->date));
4927ee54 225 }
38c6fe96 226 return $str;
4927ee54
FB
227 }
228}
8363588b 229// }}}
4927ee54 230
8363588b 231// {{{ class UFC_Registered
53eae167
RB
232/** Filters users based on registration state
233 * @param $active Whether we want to use only "active" users (i.e with a valid redirection)
234 * @param $comparison Comparison operator
235 * @param $date Date to which users registration date should be compared
236 */
4927ee54
FB
237class UFC_Registered implements UserFilterCondition
238{
239 private $active;
38c6fe96
FB
240 private $comparison;
241 private $date;
242
243 public function __construct($active = false, $comparison = null, $date = null)
4927ee54 244 {
b2e8fc54 245 $this->active = $active;
38c6fe96
FB
246 $this->comparison = $comparison;
247 $this->date = $date;
4927ee54
FB
248 }
249
dcc63ed5 250 public function buildCondition(PlFilter &$uf)
4927ee54
FB
251 {
252 if ($this->active) {
38c6fe96 253 $date = 'a.uid IS NOT NULL AND a.state = \'active\'';
4927ee54 254 } else {
38c6fe96
FB
255 $date = 'a.uid IS NOT NULL AND a.state != \'pending\'';
256 }
257 if (!is_null($this->comparison)) {
258 $date .= ' AND a.registration_date ' . $this->comparison . ' ' . XDB::format('{?}', date('Y-m-d', $this->date));
4927ee54 259 }
38c6fe96 260 return $date;
4927ee54
FB
261 }
262}
8363588b 263// }}}
4927ee54 264
8363588b 265// {{{ class UFC_ProfileUpdated
53eae167
RB
266/** Filters users based on profile update date
267 * @param $comparison Comparison operator
268 * @param $date Date to which profile update date must be compared
269 */
7e735012
FB
270class UFC_ProfileUpdated implements UserFilterCondition
271{
272 private $comparison;
273 private $date;
274
275 public function __construct($comparison = null, $date = null)
276 {
277 $this->comparison = $comparison;
278 $this->date = $date;
279 }
280
dcc63ed5 281 public function buildCondition(PlFilter &$uf)
7e735012
FB
282 {
283 return 'p.last_change ' . $this->comparison . XDB::format(' {?}', date('Y-m-d H:i:s', $this->date));
284 }
285}
8363588b 286// }}}
7e735012 287
8363588b 288// {{{ class UFC_Birthday
53eae167
RB
289/** Filters users based on next birthday date
290 * @param $comparison Comparison operator
291 * @param $date Date to which users next birthday date should be compared
292 */
7e735012
FB
293class UFC_Birthday implements UserFilterCondition
294{
295 private $comparison;
296 private $date;
297
298 public function __construct($comparison = null, $date = null)
299 {
300 $this->comparison = $comparison;
301 $this->date = $date;
302 }
303
dcc63ed5 304 public function buildCondition(PlFilter &$uf)
7e735012
FB
305 {
306 return 'p.next_birthday ' . $this->comparison . XDB::format(' {?}', date('Y-m-d', $this->date));
307 }
308}
8363588b 309// }}}
7e735012 310
8363588b 311// {{{ class UFC_Sex
53eae167
RB
312/** Filters users based on sex
313 * @parm $sex One of User::GENDER_MALE or User::GENDER_FEMALE, for selecting users
314 */
4927ee54
FB
315class UFC_Sex implements UserFilterCondition
316{
317 private $sex;
318 public function __construct($sex)
319 {
320 $this->sex = $sex;
321 }
322
dcc63ed5 323 public function buildCondition(PlFilter &$uf)
4927ee54
FB
324 {
325 if ($this->sex != User::GENDER_MALE && $this->sex != User::GENDER_FEMALE) {
326 return self::COND_FALSE;
327 } else {
24e08e33 328 return XDB::format('p.sex = {?}', $this->sex == User::GENDER_FEMALE ? 'female' : 'male');
4927ee54
FB
329 }
330 }
331}
8363588b 332// }}}
4927ee54 333
8363588b 334// {{{ class UFC_Group
53eae167 335/** Filters users based on group membership
5d2e55c7
RB
336 * @param $group Group whose members we are selecting
337 * @param $anim Whether to restrict selection to animators of that group
53eae167 338 */
4927ee54
FB
339class UFC_Group implements UserFilterCondition
340{
341 private $group;
5d2e55c7
RB
342 private $anim;
343 public function __construct($group, $anim = false)
4927ee54
FB
344 {
345 $this->group = $group;
5d2e55c7 346 $this->anim = $anim;
4927ee54
FB
347 }
348
dcc63ed5 349 public function buildCondition(PlFilter &$uf)
4927ee54
FB
350 {
351 $sub = $uf->addGroupFilter($this->group);
352 $where = 'gpm' . $sub . '.perms IS NOT NULL';
5d2e55c7 353 if ($this->anim) {
4927ee54
FB
354 $where .= ' AND gpm' . $sub . '.perms = \'admin\'';
355 }
356 return $where;
357 }
358}
8363588b 359// }}}
4927ee54 360
8363588b 361// {{{ class UFC_Email
53eae167
RB
362/** Filters users based on email address
363 * @param $email Email whose owner we are looking for
364 */
aa21c568
FB
365class UFC_Email implements UserFilterCondition
366{
367 private $email;
368 public function __construct($email)
369 {
370 $this->email = $email;
371 }
372
dcc63ed5 373 public function buildCondition(PlFilter &$uf)
aa21c568
FB
374 {
375 if (User::isForeignEmailAddress($this->email)) {
376 $sub = $uf->addEmailRedirectFilter($this->email);
377 return XDB::format('e' . $sub . '.email IS NOT NULL OR a.email = {?}', $this->email);
21401768
FB
378 } else if (User::isVirtualEmailAddress($this->email)) {
379 $sub = $uf->addVirtualEmailFilter($this->email);
380 return 'vr' . $sub . '.redirect IS NOT NULL';
aa21c568 381 } else {
21401768
FB
382 @list($user, $domain) = explode('@', $this->email);
383 $sub = $uf->addAliasFilter($user);
aa21c568
FB
384 return 'al' . $sub . '.alias IS NOT NULL';
385 }
386 }
387}
8363588b 388// }}}
d865c296 389
8363588b 390// {{{ class UFC_EmailList
5d2e55c7 391/** Filters users based on an email list
53eae167
RB
392 * @param $emails List of emails whose owner must be selected
393 */
21401768
FB
394class UFC_EmailList implements UserFilterCondition
395{
396 private $emails;
397 public function __construct($emails)
398 {
399 $this->emails = $emails;
400 }
401
dcc63ed5 402 public function buildCondition(PlFilter &$uf)
21401768
FB
403 {
404 $email = null;
405 $virtual = null;
406 $alias = null;
407 $cond = array();
408
409 if (count($this->emails) == 0) {
dcc63ed5 410 return PlFilterCondition::COND_TRUE;
21401768
FB
411 }
412
413 foreach ($this->emails as $entry) {
414 if (User::isForeignEmailAddress($entry)) {
415 if (is_null($email)) {
416 $email = $uf->addEmailRedirectFilter();
417 }
418 $cond[] = XDB::format('e' . $email . '.email = {?} OR a.email = {?}', $entry, $entry);
419 } else if (User::isVirtualEmailAddress($entry)) {
420 if (is_null($virtual)) {
421 $virtual = $uf->addVirtualEmailFilter();
422 }
423 $cond[] = XDB::format('vr' . $virtual . '.redirect IS NOT NULL AND v' . $virtual . '.alias = {?}', $entry);
424 } else {
425 if (is_null($alias)) {
426 $alias = $uf->addAliasFilter();
427 }
428 @list($user, $domain) = explode('@', $entry);
429 $cond[] = XDB::format('al' . $alias . '.alias = {?}', $user);
430 }
431 }
432 return '(' . implode(') OR (', $cond) . ')';
433 }
434}
8363588b 435// }}}
d865c296 436
8363588b 437// {{{ class UFC_Address
c4b24511 438/** Filters users based on their address
036d1637
RB
439 * @param $text Text for filter in fulltext search
440 * @param $textSearchMode Mode for search (PREFIX, SUFFIX, ...)
441 * @param $type Filter on address type
442 * @param $flags Filter on address flags
443 * @param $countryId Filter on address countryId
444 * @param $administrativeAreaId Filter on address administrativeAreaId
445 * @param $subAdministrativeAreaId Filter on address subAdministrativeAreaId
446 * @param $localityId Filter on address localityId
447 * @param $postalCode Filter on address postalCode
c4b24511
RB
448 */
449class UFC_Address implements UserFilterCondition
450{
036d1637
RB
451 /** Flags for text search
452 */
453 const PREFIX = 0x0001;
454 const SUFFIX = 0x0002;
455 const CONTAINS = 0x0003;
c4b24511 456
036d1637
RB
457 /** Valid address type ('hq' is reserved for company addresses)
458 */
459 const TYPE_HOME = 'home';
460 const TYPE_PRO = 'job';
c4b24511 461
036d1637
RB
462 /** Flags for addresses
463 */
464 const FLAG_CURRENT = 0x0001;
465 const FLAG_TEMP = 0x0002;
466 const FLAG_SECOND = 0x0004;
467 const FLAG_MAIL = 0x0008;
468 const FLAG_CEDEX = 0x0010;
469
470 // Binary OR of those flags
471 const FLAG_ANY = 0x001F;
472
473 /** Text of these flags
474 */
475 private static $flagtexts = array(
476 self::FLAG_CURRENT => 'current',
477 self::FLAG_TEMP => 'temporary',
478 self::FLAG_SECOND => 'secondary',
479 self::FLAG_MAIL => 'mail',
480 self::FLAG_CEDEX => 'cedex',
481 );
482
483 /** Data of the filter
484 */
485 private $text;
486 private $type;
487 private $flags;
488 private $countryId;
489 private $administrativeAreaId;
490 private $subAdministrativeAreaId;
491 private $localityId;
492 private $postalCode;
493
494 private $textSearchMode;
495
496 public function __construct($text = null, $textSearchMode = self::CONTAINS,
497 $type = null, $flags = self::FLAG_ANY, $countryId = null, $administrativeAreaId = null,
498 $subAdministrativeAreaId = null, $localityId = null, $postalCode = null)
499 {
500 $this->text = $text;
501 $this->textSearchMode = $textSearchMode;
502 $this->type = $type;
503 $this->flags = $flags;
504 $this->countryId = $countryId;
505 $this->administrativeAreaId = $administrativeAreaId;
506 $this->subAdministrativeAreaId = $subAdministrativeAreaId;
507 $this->localityId = $localityId;
508 $this->postalCode = $postalCode;
c4b24511
RB
509 }
510
dcc63ed5 511 public function buildCondition(PlFilter &$uf)
c4b24511 512 {
036d1637
RB
513 $sub = $uf->addAddressFilter();
514 $conds = array();
515 if ($this->text != null) {
516 $left = $sub . '.text ';
517 $op = ' LIKE ';
518 if (($this->textSearchMode & self::CONTAINS) == 0) {
519 $right = XDB::format('{?}', $this->text);
520 $op = ' = ';
521 } else if (($this->mode & self::CONTAINS) == self::PREFIX) {
522 $right = XDB::format('CONCAT({?}, \'%\')', $this->text);
523 } else if (($this->mode & self::CONTAINS) == self::SUFFIX) {
524 $right = XDB::format('CONCAT(\'%\', {?})', $this->text);
525 } else {
526 $right = XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->text);
527 }
528 $conds[] = $left . $op . $right;
c4b24511 529 }
036d1637
RB
530
531 if ($this->type != null) {
532 $conds[] = $sub . '.type = ' . XDB::format('{?}', $this->type);
533 }
534
535 if ($this->flags != self::FLAG_ANY) {
536 foreach(self::$flagtexts as $flag => $text) {
537 if ($flag & $this->flags) {
538 $conds[] = 'FIND_IN_SET(' . XDB::format('{?}', $text) . ', ' . $sub . '.flags)';
539 }
540 }
541 }
542
543 if ($this->countryId != null) {
544 $conds[] = $sub . '.countryId = ' . XDB::format('{?}', $this->countryId);
545 }
546 if ($this->administrativeAreaId != null) {
547 $conds[] = $sub . '.administrativeAreaId = ' . XDB::format('{?}', $this->administrativeAreaId);
548 }
549 if ($this->subAdministrativeAreaId != null) {
550 $conds[] = $sub . '.subAdministrativeAreaId = ' . XDB::format('{?}', $this->subAdministrativeAreaId);
551 }
552 if ($this->localityId != null) {
553 $conds[] = $sub . '.localityId = ' . XDB::format('{?}', $this->localityId);
554 }
555 if ($this->postalCode != null) {
556 $conds[] = $sub . '.postalCode = ' . XDB::format('{?}', $this->postalCode);
557 }
558
559 return implode(' AND ', $conds);
c4b24511
RB
560 }
561}
8363588b 562// }}}
c4b24511 563
8363588b 564// {{{ class UFC_Corps
4083b126
RB
565/** Filters users based on the corps they belong to
566 * @param $corps Corps we are looking for (abbreviation)
567 * @param $type Whether we search for original or current corps
568 */
569class UFC_Corps implements UserFilterCondition
570{
5d2e55c7
RB
571 const CURRENT = 1;
572 const ORIGIN = 2;
4083b126
RB
573
574 private $corps;
575 private $type;
576
577 public function __construct($corps, $type = self::CURRENT)
578 {
579 $this->corps = $corps;
580 $this->type = $type;
581 }
582
dcc63ed5 583 public function buildCondition(PlFilter &$uf)
4083b126 584 {
5d2e55c7
RB
585 /** Tables shortcuts:
586 * pc for profile_corps,
4083b126
RB
587 * pceo for profile_corps_enum - orginal
588 * pcec for profile_corps_enum - current
589 */
590 $sub = $uf->addCorpsFilter($this->type);
591 $cond = $sub . '.abbreviation = ' . $corps;
592 return $cond;
593 }
594}
8363588b 595// }}}
4083b126 596
8363588b 597// {{{ class UFC_Corps_Rank
4083b126
RB
598/** Filters users based on their rank in the corps
599 * @param $rank Rank we are looking for (abbreviation)
600 */
601class UFC_Corps_Rank implements UserFilterCondition
602{
603 private $rank;
604 public function __construct($rank)
605 {
606 $this->rank = $rank;
607 }
608
dcc63ed5 609 public function buildCondition(PlFilter &$uf)
4083b126 610 {
5d2e55c7 611 /** Tables shortcuts:
4083b126
RB
612 * pcr for profile_corps_rank
613 */
614 $sub = $uf->addCorpsRankFilter();
615 $cond = $sub . '.abbreviation = ' . $rank;
616 return $cond;
617 }
618}
8363588b 619// }}}
4083b126 620
6a99c3ac
RB
621// {{{ class UFC_Job_Company
622/** Filters users based on the company they belong to
623 * @param $type The field being searched (self::JOBID, self::JOBNAME or self::JOBACRONYM)
624 * @param $value The searched value
625 */
4e2f2ad2 626class UFC_Job_Company implements UserFilterCondition
6a99c3ac
RB
627{
628 const JOBID = 'id';
629 const JOBNAME = 'name';
630 const JOBACRONYM = 'acronym';
631
632 private $type;
633 private $value;
634
635 public function __construct($type, $value)
636 {
637 $this->assertType($type);
638 $this->type = $type;
639 $this->value = $value;
640 }
641
642 private function assertType($type)
643 {
644 if ($type != self::JOBID && $type != self::JOBNAME && $type != self::JOBACRONYM) {
5d2e55c7 645 Platal::page()->killError("Type de recherche non valide.");
6a99c3ac
RB
646 }
647 }
648
dcc63ed5 649 public function buildCondition(PlFilter &$uf)
6a99c3ac
RB
650 {
651 $sub = $uf->addJobCompanyFilter();
652 $cond = $sub . '.' . $this->type . ' = ' . XDB::format('{?}', $this->value);
653 return $cond;
654 }
655}
656// }}}
657
658// {{{ class UFC_Job_Sectorization
659/** Filters users based on the ((sub)sub)sector they work in
660 * @param $sector The sector searched
661 * @param $subsector The subsector
662 * @param $subsubsector The subsubsector
663 */
4e2f2ad2 664class UFC_Job_Sectorization implements UserFilterCondition
6a99c3ac
RB
665{
666
667 private $sector;
668 private $subsector;
669 private $subsubsector;
670
671 public function __construct($sector = null, $subsector = null, $subsubsector = null)
672 {
673 $this->sector = $sector;
674 $this->subsector = $subsector;
675 $this->subsubsector = $subsubsector;
676 }
677
dcc63ed5 678 public function buildCondition(PlFilter &$uf)
6a99c3ac
RB
679 {
680 // No need to add the JobFilter, it will be done by addJobSectorizationFilter
681 $conds = array();
682 if ($this->sector !== null) {
683 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SECTOR);
684 $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->sector);
685 }
686 if ($this->subsector !== null) {
687 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSECTOR);
688 $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->subsector);
689 }
690 if ($this->subsubsector !== null) {
691 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSUBSECTOR);
692 $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->subsubsector);
693 }
694 return implode(' AND ', $conds);
695 }
696}
697// }}}
698
699// {{{ class UFC_Job_Description
700/** Filters users based on their job description
701 * @param $description The text being searched for
702 * @param $fields The fields to search for (user-defined, ((sub|)sub|)sector)
703 */
4e2f2ad2 704class UFC_Job_Description implements UserFilterCondition
6a99c3ac
RB
705{
706
707 /** Meta-filters
708 * Built with binary OR on UserFilter::JOB_*
709 */
710 const ANY = 31;
711 const SECTORIZATION = 15;
712
713 private $description;
714 private $fields;
715
716 public function __construct($description)
717 {
718 $this->fields = $fields;
719 $this->description = $description;
720 }
721
dcc63ed5 722 public function buildCondition(PlFilter &$uf)
6a99c3ac
RB
723 {
724 $conds = array();
725 if ($this->fields & UserFilter::JOB_USERDEFINED) {
726 $sub = $uf->addJobFilter();
727 $conds[] = $sub . '.description LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
728 }
729 if ($this->fields & UserFilter::JOB_SECTOR) {
730 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SECTOR);
731 $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
732 }
733 if ($this->fields & UserFilter::JOB_SUBSECTOR) {
734 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSECTOR);
735 $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
736 }
737 if ($this->fields & UserFilter::JOB_SUBSUBSECTOR) {
738 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSUBSECTOR);
739 $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
740 $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_ALTERNATES);
741 $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
742 }
743 return implode(' OR ', $conds);
744 }
745}
746// }}}
747
0a2e9c74
RB
748// {{{ class UFC_Networking
749/** Filters users based on network identity (IRC, ...)
750 * @param $type Type of network (-1 for any)
751 * @param $value Value to search
752 */
4e2f2ad2 753class UFC_Networking implements UserFilterCondition
0a2e9c74
RB
754{
755 private $type;
756 private $value;
757
758 public function __construct($type, $value)
759 {
760 $this->type = $type;
761 $this->value = $value;
762 }
763
dcc63ed5 764 public function buildCondition(PlFilter &$uf)
0a2e9c74
RB
765 {
766 $sub = $uf->addNetworkingFilter();
767 $conds = array();
768 $conds[] = $sub . '.address = ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->value);
769 if ($this->type != -1) {
770 $conds[] = $sub . '.network_type = ' . XDB::format('{?}', $this->type);
771 }
772 return implode(' AND ', $conds);
773 }
774}
775// }}}
776
6d62969e
RB
777// {{{ class UFC_Phone
778/** Filters users based on their phone number
779 * @param $num_type Type of number (pro/user/home)
780 * @param $phone_type Type of phone (fixed/mobile/fax)
781 * @param $number Phone number
782 */
4e2f2ad2 783class UFC_Phone implements UserFilterCondition
6d62969e
RB
784{
785 const NUM_PRO = 'pro';
786 const NUM_USER = 'user';
787 const NUM_HOME = 'address';
788 const NUM_ANY = 'any';
789
790 const PHONE_FIXED = 'fixed';
791 const PHONE_MOBILE = 'mobile';
792 const PHONE_FAX = 'fax';
793 const PHONE_ANY = 'any';
794
795 private $num_type;
796 private $phone_type;
797 private $number;
798
799 public function __construct($number, $num_type = self::NUM_ANY, $phone_type = self::PHONE_ANY)
800 {
9b8e5fb4 801 require_once('profil.func.inc.php');
6d62969e
RB
802 $this->number = $number;
803 $this->num_type = $num_type;
804 $this->phone_type = format_phone_number($phone_type);
805 }
806
dcc63ed5 807 public function buildCondition(PlFilter &$uf)
6d62969e
RB
808 {
809 $sub = $uf->addPhoneFilter();
810 $conds = array();
811 $conds[] = $sub . '.search_tel = ' . XDB::format('{?}', $this->number);
812 if ($this->num_type != self::NUM_ANY) {
813 $conds[] = $sub . '.link_type = ' . XDB::format('{?}', $this->num_type);
814 }
815 if ($this->phone_type != self::PHONE_ANY) {
816 $conds[] = $sub . '.tel_type = ' . XDB::format('{?}', $this->phone_type);
817 }
818 return implode(' AND ', $conds);
819 }
820}
821// }}}
822
ceb512d2
RB
823// {{{ class UFC_Medal
824/** Filters users based on their medals
825 * @param $medal ID of the medal
826 * @param $grade Grade of the medal (null for 'any')
827 */
4e2f2ad2 828class UFC_Medal implements UserFilterCondition
ceb512d2
RB
829{
830 private $medal;
831 private $grade;
832
833 public function __construct($medal, $grade = null)
834 {
835 $this->medal = $medal;
836 $this->grade = $grade;
837 }
838
dcc63ed5 839 public function buildCondition(PlFilter &$uf)
ceb512d2
RB
840 {
841 $conds = array();
842 $sub = $uf->addMedalFilter();
843 $conds[] = $sub . '.mid = ' . XDB::format('{?}', $this->medal);
844 if ($this->grade != null) {
845 $conds[] = $sub . '.gid = ' . XDB::format('{?}', $this->grade);
846 }
847 return implode(' AND ', $conds);
848 }
849}
850// }}}
851
671b7073
RB
852// {{{ class UFC_Mentor_Expertise
853/** Filters users by mentoring expertise
854 * @param $expertise Domain of expertise
855 */
4e2f2ad2 856class UFC_Mentor_Expertise implements UserFilterCondition
671b7073
RB
857{
858 private $expertise;
859
860 public function __construct($expertise)
861 {
862 $this->expertise = $expertise;
863 }
864
dcc63ed5 865 public function buildCondition(PlFilter &$uf)
671b7073
RB
866 {
867 $sub = $uf->addMentorFilter(UserFilter::MENTOR_EXPERTISE);
868 return $sub . '.expertise LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\'', $this->expertise);
869 }
870}
871// }}}
872
873// {{{ class UFC_Mentor_Country
874/** Filters users by mentoring country
875 * @param $country Two-letters code of country being searched
876 */
4e2f2ad2 877class UFC_Mentor_Country implements UserFilterCondition
671b7073
RB
878{
879 private $country;
880
881 public function __construct($country)
882 {
883 $this->country = $country;
884 }
885
dcc63ed5 886 public function buildCondition(PlFilter &$uf)
671b7073
RB
887 {
888 $sub = $uf->addMentorFilter(UserFilter::MENTOR_COUNTRY);
889 return $sub . '.country = ' . XDB::format('{?}', $this->country);
890 }
891}
892// }}}
893
894// {{{ class UFC_Mentor_Sectorization
895/** Filters users based on mentoring (sub|)sector
896 * @param $sector ID of sector
897 * @param $subsector Subsector (null for any)
898 */
4e2f2ad2 899class UFC_Mentor_Sectorization implements UserFilterCondition
671b7073
RB
900{
901 private $sector;
902 private $subsector;
903
904 public function __construct($sector, $subsector = null)
905 {
906 $this->sector = $sector;
907 $this->subsubsector = $subsector;
908 }
909
dcc63ed5 910 public function buildCondition(PlFilter &$uf)
671b7073
RB
911 {
912 $sub = $uf->addMentorFilter(UserFilter::MENTOR_SECTOR);
913 $conds = array();
914 $conds[] = $sub . '.sectorid = ' . XDB::format('{?}', $this->sector);
915 if ($this->subsector != null) {
916 $conds[] = $sub . '.subsectorid = ' . XDB::format('{?}', $this->subsector);
917 }
918 return implode(' AND ', $conds);
919 }
920}
921// }}}
922
8363588b 923// {{{ class UFC_UserRelated
5d2e55c7 924/** Filters users based on a relation toward a user
53eae167
RB
925 * @param $user User to which searched users are related
926 */
4e7bf1e0 927abstract class UFC_UserRelated implements UserFilterCondition
3f42a6ad 928{
009b8ab7
FB
929 protected $user;
930 public function __construct(PlUser &$user)
931 {
932 $this->user =& $user;
3f42a6ad 933 }
4e7bf1e0 934}
8363588b 935// }}}
3f42a6ad 936
8363588b 937// {{{ class UFC_Contact
5d2e55c7 938/** Filters users who belong to selected user's contacts
53eae167 939 */
4e7bf1e0
FB
940class UFC_Contact extends UFC_UserRelated
941{
dcc63ed5 942 public function buildCondition(PlFilter &$uf)
3f42a6ad 943 {
009b8ab7 944 $sub = $uf->addContactFilter($this->user->id());
3f42a6ad
FB
945 return 'c' . $sub . '.contact IS NOT NULL';
946 }
947}
8363588b 948// }}}
3f42a6ad 949
8363588b 950// {{{ class UFC_WatchRegistration
53eae167
RB
951/** Filters users being watched by selected user
952 */
4e7bf1e0
FB
953class UFC_WatchRegistration extends UFC_UserRelated
954{
dcc63ed5 955 public function buildCondition(PlFilter &$uf)
4e7bf1e0 956 {
009b8ab7 957 if (!$this->user->watch('registration')) {
dcc63ed5 958 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
959 }
960 $uids = $this->user->watchUsers();
961 if (count($uids) == 0) {
dcc63ed5 962 return PlFilterCondition::COND_FALSE;
009b8ab7 963 } else {
07eb5b0e 964 return '$UID IN ' . XDB::formatArray($uids);
009b8ab7 965 }
4e7bf1e0
FB
966 }
967}
8363588b 968// }}}
4e7bf1e0 969
8363588b 970// {{{ class UFC_WatchPromo
53eae167
RB
971/** Filters users belonging to a promo watched by selected user
972 * @param $user Selected user (the one watching promo)
973 * @param $grade Formation the user is watching
974 */
4e7bf1e0
FB
975class UFC_WatchPromo extends UFC_UserRelated
976{
977 private $grade;
009b8ab7 978 public function __construct(PlUser &$user, $grade = UserFilter::GRADE_ING)
4e7bf1e0 979 {
009b8ab7 980 parent::__construct($user);
4e7bf1e0
FB
981 $this->grade = $grade;
982 }
983
dcc63ed5 984 public function buildCondition(PlFilter &$uf)
4e7bf1e0 985 {
009b8ab7
FB
986 $promos = $this->user->watchPromos();
987 if (count($promos) == 0) {
dcc63ed5 988 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
989 } else {
990 $sube = $uf->addEducationFilter(true, $this->grade);
991 $field = 'pe' . $sube . '.' . UserFilter::promoYear($this->grade);
07eb5b0e 992 return $field . ' IN ' . XDB::formatArray($promos);
009b8ab7 993 }
4e7bf1e0
FB
994 }
995}
8363588b 996// }}}
4e7bf1e0 997
8363588b 998// {{{ class UFC_WatchContact
53eae167
RB
999/** Filters users watched by selected user
1000 */
009b8ab7 1001class UFC_WatchContact extends UFC_Contact
4e7bf1e0 1002{
dcc63ed5 1003 public function buildCondition(PlFilter &$uf)
4e7bf1e0 1004 {
009b8ab7 1005 if (!$this->user->watchContacts()) {
dcc63ed5 1006 return PlFilterCondition::COND_FALSE;
009b8ab7
FB
1007 }
1008 return parent::buildCondition($uf);
4e7bf1e0
FB
1009 }
1010}
8363588b 1011// }}}
4e7bf1e0
FB
1012
1013
d865c296
FB
1014/******************
1015 * ORDERS
1016 ******************/
1017
8363588b 1018// {{{ class UserFilterOrder
2d83cac9
RB
1019/** Base class for ordering results of a query.
1020 * Parameters for the ordering must be given to the constructor ($desc for a
1021 * descending order).
1022 * The getSortTokens function is used to get actual ordering part of the query.
1023 */
7ca75030 1024abstract class UserFilterOrder extends PlFilterOrder
d865c296 1025{
2d83cac9
RB
1026 /** This function must return the tokens to use for ordering
1027 * @param &$uf The UserFilter whose results must be ordered
1028 * @return The name of the field to use for ordering results
1029 */
d865c296
FB
1030 abstract protected function getSortTokens(UserFilter &$uf);
1031}
8363588b 1032// }}}
d865c296 1033
8363588b 1034// {{{ class UFO_Promo
5d2e55c7
RB
1035/** Orders users by promotion
1036 * @param $grade Formation whose promotion users should be sorted by (restricts results to users of that formation)
53eae167
RB
1037 * @param $desc Whether sort is descending
1038 */
d865c296
FB
1039class UFO_Promo extends UserFilterOrder
1040{
1041 private $grade;
1042
1043 public function __construct($grade = null, $desc = false)
1044 {
009b8ab7 1045 parent::__construct($desc);
d865c296 1046 $this->grade = $grade;
d865c296
FB
1047 }
1048
1049 protected function getSortTokens(UserFilter &$uf)
1050 {
1051 if (UserFilter::isGrade($this->grade)) {
1052 $sub = $uf->addEducationFilter($this->grade);
1053 return 'pe' . $sub . '.' . UserFilter::promoYear($this->grade);
1054 } else {
1055 $sub = $uf->addDisplayFilter();
1056 return 'pd' . $sub . '.promo';
1057 }
1058 }
1059}
8363588b 1060// }}}
d865c296 1061
8363588b 1062// {{{ class UFO_Name
53eae167 1063/** Sorts users by name
5d2e55c7
RB
1064 * @param $type Type of name on which to sort (firstname...)
1065 * @param $variant Variant of that name to use (marital, ordinary...)
53eae167
RB
1066 * @param $particle Set to true if particles should be included in the sorting order
1067 * @param $desc If sort order should be descending
1068 */
d865c296
FB
1069class UFO_Name extends UserFilterOrder
1070{
1071 private $type;
1072 private $variant;
1073 private $particle;
1074
1075 public function __construct($type, $variant = null, $particle = false, $desc = false)
1076 {
009b8ab7 1077 parent::__construct($desc);
d865c296
FB
1078 $this->type = $type;
1079 $this->variant = $variant;
1080 $this->particle = $particle;
d865c296
FB
1081 }
1082
1083 protected function getSortTokens(UserFilter &$uf)
1084 {
1085 if (UserFilter::isDisplayName($this->type)) {
1086 $sub = $uf->addDisplayFilter();
1087 return 'pd' . $sub . '.' . $this->type;
1088 } else {
1089 $sub = $uf->addNameFilter($this->type, $this->variant);
1090 if ($this->particle) {
1091 return 'CONCAT(pn' . $sub . '.particle, \' \', pn' . $sub . '.name)';
1092 } else {
1093 return 'pn' . $sub . '.name';
1094 }
1095 }
1096 }
1097}
8363588b 1098// }}}
d865c296 1099
40585144
RB
1100// {{{ class UFO_Score
1101class UFO_Score extends UserFilterOrder
1102{
1103 protected function getSortTokens(UserFilter &$uf)
1104 {
1105 $sub = $uf->addNameTokensFilter();
1106 return 'SUM(' . $sub . '.score)';
1107 }
1108}
1109// }}}
1110
8363588b 1111// {{{ class UFO_Registration
53eae167
RB
1112/** Sorts users based on registration date
1113 */
38c6fe96
FB
1114class UFO_Registration extends UserFilterOrder
1115{
009b8ab7 1116 protected function getSortTokens(UserFilter &$uf)
38c6fe96 1117 {
009b8ab7 1118 return 'a.registration_date';
38c6fe96 1119 }
009b8ab7 1120}
8363588b 1121// }}}
38c6fe96 1122
8363588b 1123// {{{ class UFO_Birthday
53eae167
RB
1124/** Sorts users based on next birthday date
1125 */
009b8ab7
FB
1126class UFO_Birthday extends UserFilterOrder
1127{
38c6fe96
FB
1128 protected function getSortTokens(UserFilter &$uf)
1129 {
009b8ab7 1130 return 'p.next_birthday';
38c6fe96
FB
1131 }
1132}
8363588b 1133// }}}
38c6fe96 1134
8363588b 1135// {{{ class UFO_ProfileUpdate
53eae167
RB
1136/** Sorts users based on last profile update
1137 */
009b8ab7
FB
1138class UFO_ProfileUpdate extends UserFilterOrder
1139{
1140 protected function getSortTokens(UserFilter &$uf)
1141 {
1142 return 'p.last_change';
1143 }
1144}
8363588b 1145// }}}
009b8ab7 1146
8363588b 1147// {{{ class UFO_Death
53eae167
RB
1148/** Sorts users based on death date
1149 */
009b8ab7
FB
1150class UFO_Death extends UserFilterOrder
1151{
1152 protected function getSortTokens(UserFilter &$uf)
1153 {
1154 return 'p.deathdate';
1155 }
1156}
8363588b 1157// }}}
009b8ab7
FB
1158
1159
d865c296
FB
1160/***********************************
1161 *********************************
1162 USER FILTER CLASS
1163 *********************************
1164 ***********************************/
1165
8363588b 1166// {{{ class UserFilter
2d83cac9
RB
1167/** This class provides a convenient and centralized way of filtering users.
1168 *
1169 * Usage:
1170 * $uf = new UserFilter(new UFC_Blah($x, $y), new UFO_Coin($z, $t));
1171 *
1172 * Resulting UserFilter can be used to:
1173 * - get a list of User objects matching the filter
1174 * - get a list of UIDs matching the filter
1175 * - get the number of users matching the filter
1176 * - check whether a given User matches the filter
1177 * - filter a list of User objects depending on whether they match the filter
1178 *
1179 * Usage for UFC and UFO objects:
1180 * A UserFilter will call all private functions named XXXJoins.
1181 * These functions must return an array containing the list of join
1182 * required by the various UFC and UFO associated to the UserFilter.
1183 * Entries in those returned array are of the following form:
1184 * 'join_tablealias' => array('join_type', 'joined_table', 'join_criter')
1185 * which will be translated into :
1186 * join_type JOIN joined_table AS join_tablealias ON (join_criter)
1187 * in the final query.
1188 *
1189 * In the join_criter text, $ME is replaced with 'join_tablealias', $PID with
1190 * profile.pid, and $UID with auth_user_md5.user_id.
1191 *
1192 * For each kind of "JOIN" needed, a function named addXXXFilter() should be defined;
1193 * its parameter will be used to set various private vars of the UserFilter describing
1194 * the required joins ; such a function shall return the "join_tablealias" to use
1195 * when referring to the joined table.
1196 *
1197 * For example, if data from profile_job must be available to filter results,
1198 * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and
1199 * return 'pj', the short name to use when referring to profile_job; when building
1200 * the query, calling the jobJoins function will return an array containing a single
1201 * row:
1202 * 'pj' => array('left', 'profile_job', '$ME.pid = $UID');
1203 *
1204 * The 'register_optional' function can be used to generate unique table aliases when
1205 * the same table has to be joined several times with different aliases.
1206 */
9b8e5fb4 1207class UserFilter extends PlFilter
a087cc8d 1208{
9b8e5fb4 1209 protected $joinMethods = array();
7ca75030 1210
9b8e5fb4
RB
1211 protected $joinMetas = array('$PID' => 'p.pid',
1212 '$UID' => 'a.uid',
1213 );
d865c296 1214
a087cc8d 1215 private $root;
24e08e33 1216 private $sort = array();
784745ce 1217 private $query = null;
24e08e33 1218 private $orderby = null;
784745ce 1219
aa21c568 1220 private $lastcount = null;
d865c296 1221
24e08e33 1222 public function __construct($cond = null, $sort = null)
5dd9d823 1223 {
06598c13 1224 if (empty($this->joinMethods)) {
d865c296
FB
1225 $class = new ReflectionClass('UserFilter');
1226 foreach ($class->getMethods() as $method) {
1227 $name = $method->getName();
1228 if (substr($name, -5) == 'Joins' && $name != 'buildJoins') {
06598c13 1229 $this->joinMethods[] = $name;
d865c296
FB
1230 }
1231 }
1232 }
5dd9d823 1233 if (!is_null($cond)) {
06598c13 1234 if ($cond instanceof PlFilterCondition) {
5dd9d823
FB
1235 $this->setCondition($cond);
1236 }
1237 }
24e08e33
FB
1238 if (!is_null($sort)) {
1239 if ($sort instanceof UserFilterOrder) {
1240 $this->addSort($sort);
d865c296
FB
1241 } else if (is_array($sort)) {
1242 foreach ($sort as $s) {
1243 $this->addSort($s);
1244 }
24e08e33
FB
1245 }
1246 }
5dd9d823
FB
1247 }
1248
784745ce
FB
1249 private function buildQuery()
1250 {
d865c296
FB
1251 if (is_null($this->orderby)) {
1252 $orders = array();
1253 foreach ($this->sort as $sort) {
1254 $orders = array_merge($orders, $sort->buildSort($this));
1255 }
1256 if (count($orders) == 0) {
1257 $this->orderby = '';
1258 } else {
1259 $this->orderby = 'ORDER BY ' . implode(', ', $orders);
1260 }
1261 }
784745ce
FB
1262 if (is_null($this->query)) {
1263 $where = $this->root->buildCondition($this);
f7ea7450
RB
1264 if ($this->with_forced_sn) {
1265 $this->requireProfiles();
1266 $from = 'search_name AS sn';
1267 } else if ($this->with_accounts) {
b8dcf62d
RB
1268 $from = 'accounts AS a';
1269 } else {
1270 $this->requireProfiles();
1271 $from = 'profiles AS p';
1272 }
f7ea7450 1273 $joins = $this->buildJoins();
b8dcf62d 1274 $this->query = 'FROM ' . $from . '
784745ce
FB
1275 ' . $joins . '
1276 WHERE (' . $where . ')';
1277 }
1278 }
1279
7ca75030 1280 private function getUIDList($uids = null, PlLimit &$limit)
d865c296 1281 {
b8dcf62d 1282 $this->requireAccounts();
d865c296 1283 $this->buildQuery();
7ca75030 1284 $lim = $limit->getSql();
d865c296
FB
1285 $cond = '';
1286 if (!is_null($uids)) {
07eb5b0e 1287 $cond = ' AND a.uid IN ' . XDB::formatArray($uids);
d865c296
FB
1288 }
1289 $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid
1290 ' . $this->query . $cond . '
1291 GROUP BY a.uid
1292 ' . $this->orderby . '
7ca75030 1293 ' . $lim);
d865c296
FB
1294 $this->lastcount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
1295 return $fetched;
1296 }
1297
043b104b
RB
1298 private function getPIDList($pids = null, PlLimit &$limit)
1299 {
1300 $this->requireProfiles();
1301 $this->buildQuery();
1302 $lim = $limit->getSql();
1303 $cond = '';
1304 if (!is_null($pids)) {
1305 $cond = ' AND p.pid IN ' . XDB::formatArray($pids);
1306 }
1307 $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS p.pid
1308 ' . $this->query . $cond . '
1309 GROUP BY p.pid
1310 ' . $this->orderby . '
1311 ' . $lim);
1312 $this->lastcount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
1313 return $fetched;
1314 }
1315
a087cc8d
FB
1316 /** Check that the user match the given rule.
1317 */
1318 public function checkUser(PlUser &$user)
1319 {
b8dcf62d 1320 $this->requireAccounts();
784745ce
FB
1321 $this->buildQuery();
1322 $count = (int)XDB::fetchOneCell('SELECT COUNT(*)
1323 ' . $this->query . XDB::format(' AND a.uid = {?}', $user->id()));
1324 return $count == 1;
a087cc8d
FB
1325 }
1326
043b104b
RB
1327 /** Check that the profile match the given rule.
1328 */
1329 public function checkProfile(Profile &$profile)
1330 {
1331 $this->requireProfiles();
1332 $this->buildQuery();
1333 $count = (int)XDB::fetchOneCell('SELECT COUNT(*)
1334 ' . $this->query . XDB::format(' AND p.pid = {?}', $profile->id()));
1335 return $count == 1;
1336 }
1337
1338 /** Default filter is on users
a087cc8d 1339 */
7ca75030 1340 public function filter(array $users, PlLimit &$limit)
a087cc8d 1341 {
043b104b
RB
1342 return $this->filterUsers($users, $limit);
1343 }
1344
1345 /** Filter a list of users to extract the users matching the rule.
1346 */
1347 public function filterUsers(array $users, PlLimit &$limit)
1348 {
b8dcf62d 1349 $this->requireAccounts();
4927ee54
FB
1350 $this->buildQuery();
1351 $table = array();
1352 $uids = array();
1353 foreach ($users as $user) {
07eb5b0e
FB
1354 if ($user instanceof PlUser) {
1355 $uid = $user->id();
1356 } else {
1357 $uid = $user;
1358 }
1359 $uids[] = $uid;
1360 $table[$uid] = $user;
4927ee54 1361 }
7ca75030 1362 $fetched = $this->getUIDList($uids, $limit);
a087cc8d 1363 $output = array();
4927ee54
FB
1364 foreach ($fetched as $uid) {
1365 $output[] = $table[$uid];
a087cc8d
FB
1366 }
1367 return $output;
1368 }
1369
043b104b
RB
1370 /** Filter a list of profiles to extract the users matching the rule.
1371 */
1372 public function filterProfiles(array $profiles, PlLimit &$limit)
1373 {
1374 $this->requireProfiles();
1375 $this->buildQuery();
1376 $table = array();
1377 $pids = array();
1378 foreach ($profiles as $profile) {
1379 if ($profile instanceof Profile) {
1380 $pid = $profile->id();
1381 } else {
1382 $pid = $profile;
1383 }
1384 $pids[] = $pid;
1385 $table[$pid] = $profile;
1386 }
1387 $fetched = $this->getPIDList($pids, $limit);
1388 $output = array();
1389 foreach ($fetched as $pid) {
1390 $output[] = $table[$pid];
1391 }
1392 return $output;
1393 }
1394
7ca75030
RB
1395 public function getUIDs(PlLimit &$limit)
1396 {
1397 return $this->getUIDList(null, $limit);
1398 }
1399
043b104b
RB
1400 public function getPIDs(PlLimit &$limit)
1401 {
1402 return $this->getPIDList(null, $limit);
1403 }
1404
7ca75030 1405 public function getUsers(PlLimit &$limit)
4927ee54 1406 {
7ca75030 1407 return User::getBulkUsersWithUIDs($this->getUIDs($limit));
d865c296
FB
1408 }
1409
043b104b
RB
1410 public function getProfiles(PlLimit &$limit)
1411 {
1412 return Profile::getBulkProfilesWithPIDs($this->getPIDs($limit));
1413 }
1414
7ca75030 1415 public function get(PlLimit &$limit)
d865c296 1416 {
7ca75030 1417 return $this->getUsers($limit);
4927ee54
FB
1418 }
1419
d865c296 1420 public function getTotalCount()
4927ee54 1421 {
38c6fe96 1422 if (is_null($this->lastcount)) {
aa21c568 1423 $this->buildQuery();
b8dcf62d
RB
1424 if ($this->requireAccounts()) {
1425 $field = 'a.uid';
1426 } else {
1427 $field = 'p.pid';
1428 }
1429 return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT ' . $field . ')
7e735012 1430 ' . $this->query);
38c6fe96
FB
1431 } else {
1432 return $this->lastcount;
1433 }
4927ee54
FB
1434 }
1435
9b8e5fb4 1436 public function setCondition(PlFilterCondition &$cond)
a087cc8d
FB
1437 {
1438 $this->root =& $cond;
784745ce 1439 $this->query = null;
a087cc8d
FB
1440 }
1441
9b8e5fb4 1442 public function addSort(PlFilterOrder &$sort)
24e08e33 1443 {
d865c296
FB
1444 $this->sort[] = $sort;
1445 $this->orderby = null;
24e08e33
FB
1446 }
1447
a087cc8d
FB
1448 static public function getLegacy($promo_min, $promo_max)
1449 {
a087cc8d 1450 if ($promo_min != 0) {
784745ce 1451 $min = new UFC_Promo('>=', self::GRADE_ING, intval($promo_min));
5dd9d823
FB
1452 } else {
1453 $min = new UFC_True();
a087cc8d 1454 }
a087cc8d 1455 if ($promo_max != 0) {
784745ce 1456 $max = new UFC_Promo('<=', self::GRADE_ING, intval($promo_max));
a087cc8d 1457 } else {
5dd9d823 1458 $max = new UFC_True();
a087cc8d 1459 }
9b8e5fb4 1460 return new UserFilter(new PFC_And($min, $max));
a087cc8d 1461 }
784745ce 1462
07eb5b0e
FB
1463 static public function sortByName()
1464 {
1465 return array(new UFO_Name(self::LASTNAME), new UFO_Name(self::FIRSTNAME));
1466 }
1467
1468 static public function sortByPromo()
1469 {
1470 return array(new UFO_Promo(), new UFO_Name(self::LASTNAME), new UFO_Name(self::FIRSTNAME));
1471 }
1472
aa21c568
FB
1473 static private function getDBSuffix($string)
1474 {
1475 return preg_replace('/[^a-z0-9]/i', '', $string);
1476 }
1477
1478
2d83cac9
RB
1479 /** Stores a new (and unique) table alias in the &$table table
1480 * @param &$table Array in which the table alias must be stored
1481 * @param $val Value which will then be used to build the join
1482 * @return Name of the newly created alias
1483 */
aa21c568
FB
1484 private $option = 0;
1485 private function register_optional(array &$table, $val)
1486 {
1487 if (is_null($val)) {
1488 $sub = $this->option++;
1489 $index = null;
1490 } else {
1491 $sub = self::getDBSuffix($val);
1492 $index = $val;
1493 }
1494 $sub = '_' . $sub;
1495 $table[$sub] = $index;
1496 return $sub;
1497 }
784745ce 1498
b8dcf62d
RB
1499 /** PROFILE VS ACCOUNT
1500 */
f7ea7450
RB
1501 private $with_profiles = false;
1502 private $with_accounts = false;
1503 private $with_forced_sn = false;
b8dcf62d
RB
1504 public function requireAccounts()
1505 {
1506 $this->with_accounts = true;
1507 }
1508
1509 public function requireProfiles()
1510 {
1511 $this->with_profiles = true;
1512 }
1513
f7ea7450
RB
1514 /** Forces the "FROM" to use search_name instead of accounts or profiles */
1515 public function forceSearchName()
1516 {
1517 $this->with_forced_sn = true;
1518 }
1519
b8dcf62d
RB
1520 protected function accountJoins()
1521 {
1522 $joins = array();
f7ea7450
RB
1523 /** Quick search is much more efficient with sn first and PID second */
1524 if ($this->with_forced_sn) {
1525 $joins['p'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profiles', '$PID = sn.uid');
1526 if ($this->with_accounts) {
1527 $joins['ap'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'account_profiles', '$ME.pid = $PID');
1528 $joins['a'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'accounts', '$UID = ap.uid');
1529 }
1530 } else if ($this->with_profiles && $this->with_accounts) {
b8dcf62d
RB
1531 $joins['ap'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'account_profiles', '$ME.uid = $UID AND FIND_IN_SET(\'owner\', ap.perms)');
1532 $joins['p'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profiles', '$PID = ap.pid');
1533 }
1534 return $joins;
1535 }
1536
d865c296
FB
1537 /** DISPLAY
1538 */
38c6fe96 1539 const DISPLAY = 'display';
d865c296
FB
1540 private $pd = false;
1541 public function addDisplayFilter()
1542 {
b8dcf62d 1543 $this->requireProfiles();
d865c296
FB
1544 $this->pd = true;
1545 return '';
1546 }
1547
9b8e5fb4 1548 protected function displayJoins()
d865c296
FB
1549 {
1550 if ($this->pd) {
7ca75030 1551 return array('pd' => new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_display', '$ME.pid = $PID'));
d865c296
FB
1552 } else {
1553 return array();
1554 }
1555 }
1556
784745ce
FB
1557 /** NAMES
1558 */
d865c296 1559 /* name tokens */
784745ce
FB
1560 const LASTNAME = 'lastname';
1561 const FIRSTNAME = 'firstname';
1562 const NICKNAME = 'nickname';
1563 const PSEUDONYM = 'pseudonym';
1564 const NAME = 'name';
d865c296 1565 /* name variants */
784745ce
FB
1566 const VN_MARITAL = 'marital';
1567 const VN_ORDINARY = 'ordinary';
1568 const VN_OTHER = 'other';
1569 const VN_INI = 'ini';
d865c296
FB
1570 /* display names */
1571 const DN_FULL = 'directory_name';
1572 const DN_DISPLAY = 'yourself';
1573 const DN_YOURSELF = 'yourself';
1574 const DN_DIRECTORY = 'directory_name';
1575 const DN_PRIVATE = 'private_name';
1576 const DN_PUBLIC = 'public_name';
1577 const DN_SHORT = 'short_name';
1578 const DN_SORT = 'sort_name';
784745ce
FB
1579
1580 static public $name_variants = array(
1581 self::LASTNAME => array(self::VN_MARITAL, self::VN_ORDINARY),
d865c296
FB
1582 self::FIRSTNAME => array(self::VN_ORDINARY, self::VN_INI, self::VN_OTHER)
1583 );
784745ce
FB
1584
1585 static public function assertName($name)
1586 {
1587 if (!Profile::getNameTypeId($name)) {
9b8e5fb4 1588 Platal::page()->kill('Invalid name type: ' . $name);
784745ce
FB
1589 }
1590 }
1591
d865c296
FB
1592 static public function isDisplayName($name)
1593 {
1594 return $name == self::DN_FULL || $name == self::DN_DISPLAY
1595 || $name == self::DN_YOURSELF || $name == self::DN_DIRECTORY
1596 || $name == self::DN_PRIVATE || $name == self::DN_PUBLIC
1597 || $name == self::DN_SHORT || $name == self::DN_SORT;
1598 }
1599
784745ce 1600 private $pn = array();
784745ce
FB
1601 public function addNameFilter($type, $variant = null)
1602 {
b8dcf62d 1603 $this->requireProfiles();
784745ce
FB
1604 if (!is_null($variant)) {
1605 $ft = $type . '_' . $variant;
1606 } else {
1607 $ft = $type;
1608 }
1609 $sub = '_' . $ft;
1610 self::assertName($ft);
1611
1612 if (!is_null($variant) && $variant == 'other') {
aa21c568 1613 $sub .= $this->option++;
784745ce
FB
1614 }
1615 $this->pn[$sub] = Profile::getNameTypeId($ft);
1616 return $sub;
1617 }
1618
9b8e5fb4 1619 protected function nameJoins()
784745ce
FB
1620 {
1621 $joins = array();
1622 foreach ($this->pn as $sub => $type) {
7ca75030 1623 $joins['pn' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_name', '$ME.pid = $PID AND $ME.typeid = ' . $type);
784745ce
FB
1624 }
1625 return $joins;
1626 }
1627
40585144
RB
1628 /** NAMETOKENS
1629 */
1630 private $with_sn = false;
f7ea7450
RB
1631 // Set $doingQuickSearch to true if you wish to optimize the query
1632 public function addNameTokensFilter($doingQuickSearch = false)
40585144
RB
1633 {
1634 $this->requireProfiles();
f7ea7450 1635 $this->with_forced_sn = ($this->with_forced_sn || $doingQuickSearch);
40585144
RB
1636 $this->with_sn = true;
1637 return 'sn';
1638 }
1639
1640 protected function nameTokensJoins()
1641 {
f7ea7450
RB
1642 /* We don't return joins, since with_sn forces the SELECT to run on search_name first */
1643 if ($this->with_sn && !$this->with_forced_sn) {
1644 return array(
1645 'sn' => new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'search_name', '$ME.uid = $PID')
1646 );
1647 } else {
1648 return array();
40585144 1649 }
40585144
RB
1650 }
1651
784745ce
FB
1652 /** EDUCATION
1653 */
1654 const GRADE_ING = 'Ing.';
1655 const GRADE_PHD = 'PhD';
1656 const GRADE_MST = 'M%';
1657 static public function isGrade($grade)
1658 {
38c6fe96 1659 return $grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST;
784745ce
FB
1660 }
1661
1662 static public function assertGrade($grade)
1663 {
1664 if (!self::isGrade($grade)) {
1665 Platal::page()->killError("Diplôme non valide");
1666 }
1667 }
1668
d865c296
FB
1669 static public function promoYear($grade)
1670 {
1671 // XXX: Definition of promotion for phds and masters might change in near future.
1672 return ($grade == UserFilter::GRADE_ING) ? 'entry_year' : 'grad_year';
1673 }
1674
784745ce
FB
1675 private $pepe = array();
1676 private $with_pee = false;
784745ce
FB
1677 public function addEducationFilter($x = false, $grade = null)
1678 {
b8dcf62d 1679 $this->requireProfiles();
784745ce 1680 if (!$x) {
aa21c568
FB
1681 $index = $this->option;
1682 $sub = $this->option++;
784745ce
FB
1683 } else {
1684 self::assertGrade($grade);
1685 $index = $grade;
1686 $sub = $grade[0];
1687 $this->with_pee = true;
1688 }
1689 $sub = '_' . $sub;
1690 $this->pepe[$index] = $sub;
1691 return $sub;
1692 }
1693
9b8e5fb4 1694 protected function educationJoins()
784745ce
FB
1695 {
1696 $joins = array();
1697 if ($this->with_pee) {
7ca75030 1698 $joins['pee'] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'profile_education_enum', 'pee.abbreviation = \'X\'');
784745ce
FB
1699 }
1700 foreach ($this->pepe as $grade => $sub) {
1701 if ($this->isGrade($grade)) {
7ca75030
RB
1702 $joins['pe' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_education', '$ME.eduid = pee.id AND $ME.uid = $PID');
1703 $joins['pede' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid AND $ME.abbreviation LIKE ' .
784745ce
FB
1704 XDB::format('{?}', $grade));
1705 } else {
7ca75030
RB
1706 $joins['pe' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_education', '$ME.uid = $PID');
1707 $joins['pee' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'profile_education_enum', '$ME.id = pe' . $sub . '.eduid');
1708 $joins['pede' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid');
784745ce
FB
1709 }
1710 }
1711 return $joins;
1712 }
4927ee54
FB
1713
1714
1715 /** GROUPS
1716 */
1717 private $gpm = array();
4927ee54
FB
1718 public function addGroupFilter($group = null)
1719 {
b8dcf62d 1720 $this->requireAccounts();
4927ee54
FB
1721 if (!is_null($group)) {
1722 if (ctype_digit($group)) {
1723 $index = $sub = $group;
1724 } else {
1725 $index = $group;
aa21c568 1726 $sub = self::getDBSuffix($group);
4927ee54
FB
1727 }
1728 } else {
aa21c568 1729 $sub = 'group_' . $this->option++;
4927ee54
FB
1730 $index = null;
1731 }
1732 $sub = '_' . $sub;
1733 $this->gpm[$sub] = $index;
1734 return $sub;
1735 }
1736
9b8e5fb4 1737 protected function groupJoins()
4927ee54
FB
1738 {
1739 $joins = array();
1740 foreach ($this->gpm as $sub => $key) {
1741 if (is_null($key)) {
7ca75030
RB
1742 $joins['gpa' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'groupex.asso');
1743 $joins['gpm' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'groupex.membres', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4927ee54 1744 } else if (ctype_digit($key)) {
7ca75030 1745 $joins['gpm' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'groupex.membres', '$ME.uid = $UID AND $ME.asso_id = ' . $key);
4927ee54 1746 } else {
7ca75030
RB
1747 $joins['gpa' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_INNER, 'groupex.asso', XDB::format('$ME.diminutif = {?}', $key));
1748 $joins['gpm' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'groupex.membres', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4927ee54
FB
1749 }
1750 }
1751 return $joins;
1752 }
aa21c568
FB
1753
1754 /** EMAILS
1755 */
1756 private $e = array();
1757 public function addEmailRedirectFilter($email = null)
1758 {
b8dcf62d 1759 $this->requireAccounts();
aa21c568
FB
1760 return $this->register_optional($this->e, $email);
1761 }
1762
1763 private $ve = array();
1764 public function addVirtualEmailFilter($email = null)
1765 {
21401768 1766 $this->addAliasFilter(self::ALIAS_FORLIFE);
aa21c568
FB
1767 return $this->register_optional($this->ve, $email);
1768 }
1769
21401768
FB
1770 const ALIAS_BEST = 'bestalias';
1771 const ALIAS_FORLIFE = 'forlife';
aa21c568
FB
1772 private $al = array();
1773 public function addAliasFilter($alias = null)
1774 {
b8dcf62d 1775 $this->requireAccounts();
aa21c568
FB
1776 return $this->register_optional($this->al, $alias);
1777 }
1778
9b8e5fb4 1779 protected function emailJoins()
aa21c568
FB
1780 {
1781 global $globals;
1782 $joins = array();
1783 foreach ($this->e as $sub=>$key) {
1784 if (is_null($key)) {
7ca75030 1785 $joins['e' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'emails', '$ME.uid = $UID AND $ME.flags != \'filter\'');
aa21c568 1786 } else {
7ca75030 1787 $joins['e' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'emails', XDB::format('$ME.uid = $UID AND $ME.flags != \'filter\' AND $ME.email = {?}', $key));
aa21c568
FB
1788 }
1789 }
21401768 1790 foreach ($this->al as $sub=>$key) {
aa21c568 1791 if (is_null($key)) {
7ca75030 1792 $joins['al' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'aliases', '$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\')');
21401768 1793 } else if ($key == self::ALIAS_BEST) {
7ca75030 1794 $joins['al' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'aliases', '$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND FIND_IN_SET(\'bestalias\', $ME.flags)');
21401768 1795 } else if ($key == self::ALIAS_FORLIFE) {
7ca75030 1796 $joins['al' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'aliases', '$ME.id = $UID AND $ME.type = \'a_vie\'');
aa21c568 1797 } else {
7ca75030 1798 $joins['al' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'aliases', XDB::format('$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND $ME.alias = {?}', $key));
aa21c568 1799 }
aa21c568 1800 }
21401768 1801 foreach ($this->ve as $sub=>$key) {
aa21c568 1802 if (is_null($key)) {
7ca75030 1803 $joins['v' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'virtual', '$ME.type = \'user\'');
aa21c568 1804 } else {
7ca75030 1805 $joins['v' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'virtual', XDB::format('$ME.type = \'user\' AND $ME.alias = {?}', $key));
aa21c568 1806 }
7ca75030 1807 $joins['vr' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'virtual_redirect', XDB::format('$ME.vid = v' . $sub . '.vid
21401768
FB
1808 AND ($ME.redirect IN (CONCAT(al_forlife.alias, \'@\', {?}),
1809 CONCAT(al_forlife.alias, \'@\', {?}),
1810 a.email))',
1811 $globals->mail->domain, $globals->mail->domain2));
aa21c568
FB
1812 }
1813 return $joins;
1814 }
3f42a6ad
FB
1815
1816
c4b24511
RB
1817 /** ADDRESSES
1818 */
036d1637 1819 private $with_pa = false;
c4b24511
RB
1820 public function addAddressFilter()
1821 {
b8dcf62d 1822 $this->requireProfiles();
036d1637
RB
1823 $this->with_pa = true;
1824 return 'pa';
c4b24511
RB
1825 }
1826
9b8e5fb4 1827 protected function addressJoins()
c4b24511
RB
1828 {
1829 $joins = array();
036d1637 1830 if ($this->with_pa) {
7ca75030 1831 $joins['pa'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_address', '$ME.pid = $PID');
c4b24511
RB
1832 }
1833 return $joins;
1834 }
1835
1836
4083b126
RB
1837 /** CORPS
1838 */
1839
1840 private $pc = false;
1841 private $pce = array();
1842 private $pcr = false;
1843 public function addCorpsFilter($type)
1844 {
b8dcf62d 1845 $this->requireProfiles();
4083b126
RB
1846 $this->pc = true;
1847 if ($type == UFC_Corps::CURRENT) {
1848 $pce['pcec'] = 'current_corpsid';
1849 return 'pcec';
1850 } else if ($type == UFC_Corps::ORIGIN) {
1851 $pce['pceo'] = 'original_corpsid';
1852 return 'pceo';
1853 }
1854 }
1855
1856 public function addCorpsRankFilter()
1857 {
b8dcf62d 1858 $this->requireProfiles();
4083b126
RB
1859 $this->pc = true;
1860 $this->pcr = true;
1861 return 'pcr';
1862 }
1863
9b8e5fb4 1864 protected function corpsJoins()
4083b126
RB
1865 {
1866 $joins = array();
1867 if ($this->pc) {
7ca75030 1868 $joins['pc'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_corps', '$ME.uid = $UID');
4083b126
RB
1869 }
1870 if ($this->pcr) {
7ca75030 1871 $joins['pcr'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_corps_rank_enum', '$ME.id = pc.rankid');
4083b126
RB
1872 }
1873 foreach($this->pce as $sub => $field) {
7ca75030 1874 $joins[$sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_corps_enum', '$ME.id = pc.' . $field);
4083b126
RB
1875 }
1876 return $joins;
1877 }
1878
6a99c3ac
RB
1879 /** JOBS
1880 */
1881
1882 const JOB_SECTOR = 1;
1883 const JOB_SUBSECTOR = 2;
1884 const JOB_SUBSUBSECTOR = 4;
1885 const JOB_ALTERNATES = 8;
1886 const JOB_USERDEFINED = 16;
1887
1888 /** Joins :
1889 * pj => profile_job
1890 * pje => profile_job_enum
1891 * pjse => profile_job_sector_enum
1892 * pjsse => profile_job_subsector_enum
1893 * pjssse => profile_job_subsubsector_enum
1894 * pja => profile_job_alternates
1895 */
1896 private $with_pj = false;
1897 private $with_pje = false;
1898 private $with_pjse = false;
1899 private $with_pjsse = false;
1900 private $with_pjssse = false;
1901 private $with_pja = false;
1902
1903 public function addJobFilter()
1904 {
b8dcf62d 1905 $this->requireProfiles();
6a99c3ac
RB
1906 $this->with_pj = true;
1907 return 'pj';
1908 }
1909
1910 public function addJobCompanyFilter()
1911 {
1912 $this->addJobFilter();
1913 $this->with_pje = true;
1914 return 'pje';
1915 }
1916
1917 public function addJobSectorizationFilter($type)
1918 {
1919 $this->addJobFilter();
1920 if ($type == self::JOB_SECTOR) {
1921 $this->with_pjse = true;
1922 return 'pjse';
1923 } else if ($type == self::JOB_SUBSECTOR) {
1924 $this->with_pjsse = true;
1925 return 'pjsse';
1926 } else if ($type == self::JOB_SUBSUBSECTOR) {
1927 $this->with_pjssse = true;
1928 return 'pjssse';
1929 } else if ($type == self::JOB_ALTERNATES) {
1930 $this->with_pja = true;
1931 return 'pja';
1932 }
1933 }
1934
9b8e5fb4 1935 protected function jobJoins()
6a99c3ac
RB
1936 {
1937 $joins = array();
1938 if ($this->with_pj) {
7ca75030 1939 $joins['pj'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job', '$ME.uid = $UID');
6a99c3ac
RB
1940 }
1941 if ($this->with_pje) {
7ca75030 1942 $joins['pje'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job_enum', '$ME.id = pj.jobid');
6a99c3ac
RB
1943 }
1944 if ($this->with_pjse) {
7ca75030 1945 $joins['pjse'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job_sector_enum', '$ME.id = pj.sectorid');
6a99c3ac
RB
1946 }
1947 if ($this->with_pjsse) {
7ca75030 1948 $joins['pjsse'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job_subsector_enum', '$ME.id = pj.subsectorid');
6a99c3ac
RB
1949 }
1950 if ($this->with_pjssse) {
7ca75030 1951 $joins['pjssse'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job_subsubsector_enum', '$ME.id = pj.subsubsectorid');
6a99c3ac
RB
1952 }
1953 if ($this->with_pja) {
7ca75030 1954 $joins['pja'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_job_alternates', '$ME.subsubsectorid = pj.subsubsectorid');
6a99c3ac
RB
1955 }
1956 return $joins;
1957 }
1958
0a2e9c74
RB
1959 /** NETWORKING
1960 */
1961
1962 private $with_pnw = false;
1963 public function addNetworkingFilter()
1964 {
b8dcf62d 1965 $this->requireAccounts();
0a2e9c74
RB
1966 $this->with_pnw = true;
1967 return 'pnw';
1968 }
1969
9b8e5fb4 1970 protected function networkingJoins()
0a2e9c74
RB
1971 {
1972 $joins = array();
1973 if ($this->with_pnw) {
7ca75030 1974 $joins['pnw'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_networking', '$ME.uid = $UID');
0a2e9c74
RB
1975 }
1976 return $joins;
1977 }
1978
6d62969e
RB
1979 /** PHONE
1980 */
1981
2d83cac9 1982 private $with_ptel = false;
6d62969e
RB
1983
1984 public function addPhoneFilter()
1985 {
b8dcf62d 1986 $this->requireAccounts();
2d83cac9 1987 $this->with_ptel = true;
6d62969e
RB
1988 return 'ptel';
1989 }
1990
9b8e5fb4 1991 protected function phoneJoins()
6d62969e
RB
1992 {
1993 $joins = array();
2d83cac9 1994 if ($this->with_ptel) {
9b8e5fb4 1995 $joins['ptel'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_phones', '$ME.uid = $UID');
6d62969e
RB
1996 }
1997 return $joins;
1998 }
1999
ceb512d2
RB
2000 /** MEDALS
2001 */
2002
2d83cac9 2003 private $with_pmed = false;
ceb512d2
RB
2004 public function addMedalFilter()
2005 {
b8dcf62d 2006 $this->requireProfiles();
2d83cac9 2007 $this->with_pmed = true;
ceb512d2
RB
2008 return 'pmed';
2009 }
2010
9b8e5fb4 2011 protected function medalJoins()
ceb512d2
RB
2012 {
2013 $joins = array();
2d83cac9 2014 if ($this->with_pmed) {
7ca75030 2015 $joins['pmed'] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'profile_medals_sub', '$ME.uid = $UID');
ceb512d2
RB
2016 }
2017 return $joins;
2018 }
2019
671b7073
RB
2020 /** MENTORING
2021 */
2022
2023 private $pms = array();
2024 const MENTOR_EXPERTISE = 1;
2025 const MENTOR_COUNTRY = 2;
2026 const MENTOR_SECTOR = 3;
2027
2028 public function addMentorFilter($type)
2029 {
b8dcf62d 2030 $this->requireAccounts();
671b7073
RB
2031 switch($type) {
2032 case MENTOR_EXPERTISE:
2033 $pms['pme'] = 'profile_mentor';
2034 return 'pme';
2035 case MENTOR_COUNTRY:
2036 $pms['pmc'] = 'profile_mentor_country';
2037 return 'pmc';
2038 case MENTOR_SECTOR:
2039 $pms['pms'] = 'profile_mentor_sector';
2040 return 'pms';
2041 default:
5d2e55c7 2042 Platal::page()->killError("Undefined mentor filter.");
671b7073
RB
2043 }
2044 }
2045
9b8e5fb4 2046 protected function mentorJoins()
671b7073
RB
2047 {
2048 $joins = array();
2049 foreach ($this->pms as $sub => $tab) {
7ca75030 2050 $joins[$sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, $tab, '$ME.uid = $UID');
671b7073
RB
2051 }
2052 return $joins;
2053 }
2054
3f42a6ad
FB
2055 /** CONTACTS
2056 */
2057 private $cts = array();
2058 public function addContactFilter($uid = null)
2059 {
b8dcf62d 2060 $this->requireAccounts();
3f42a6ad
FB
2061 return $this->register_optional($this->cts, is_null($uid) ? null : 'user_' . $uid);
2062 }
2063
9b8e5fb4 2064 protected function contactJoins()
3f42a6ad
FB
2065 {
2066 $joins = array();
2067 foreach ($this->cts as $sub=>$key) {
2068 if (is_null($key)) {
7ca75030 2069 $joins['c' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'contacts', '$ME.contact = $UID');
3f42a6ad 2070 } else {
7ca75030 2071 $joins['c' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'contacts', XDB::format('$ME.uid = {?} AND $ME.contact = $UID', substr($key, 5)));
3f42a6ad
FB
2072 }
2073 }
2074 return $joins;
2075 }
4e7bf1e0
FB
2076
2077
2078 /** CARNET
2079 */
2080 private $wn = array();
2081 public function addWatchRegistrationFilter($uid = null)
2082 {
b8dcf62d 2083 $this->requireAccounts();
4e7bf1e0
FB
2084 return $this->register_optional($this->wn, is_null($uid) ? null : 'user_' . $uid);
2085 }
2086
2087 private $wp = array();
2088 public function addWatchPromoFilter($uid = null)
2089 {
b8dcf62d 2090 $this->requireAccounts();
4e7bf1e0
FB
2091 return $this->register_optional($this->wp, is_null($uid) ? null : 'user_' . $uid);
2092 }
2093
2094 private $w = array();
2095 public function addWatchFilter($uid = null)
2096 {
b8dcf62d 2097 $this->requireAccounts();
4e7bf1e0
FB
2098 return $this->register_optional($this->w, is_null($uid) ? null : 'user_' . $uid);
2099 }
2100
9b8e5fb4 2101 protected function watchJoins()
4e7bf1e0
FB
2102 {
2103 $joins = array();
2104 foreach ($this->w as $sub=>$key) {
2105 if (is_null($key)) {
7ca75030 2106 $joins['w' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch');
4e7bf1e0 2107 } else {
7ca75030 2108 $joins['w' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch', XDB::format('$ME.uid = {?}', substr($key, 5)));
4e7bf1e0
FB
2109 }
2110 }
2111 foreach ($this->wn as $sub=>$key) {
2112 if (is_null($key)) {
7ca75030 2113 $joins['wn' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 2114 } else {
7ca75030 2115 $joins['wn' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_nonins', XDB::format('$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5)));
4e7bf1e0
FB
2116 }
2117 }
2118 foreach ($this->wn as $sub=>$key) {
2119 if (is_null($key)) {
7ca75030 2120 $joins['wn' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 2121 } else {
7ca75030 2122 $joins['wn' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_nonins', XDB::format('$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5)));
4e7bf1e0
FB
2123 }
2124 }
2125 foreach ($this->wp as $sub=>$key) {
2126 if (is_null($key)) {
7ca75030 2127 $joins['wp' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_promo');
4e7bf1e0 2128 } else {
7ca75030 2129 $joins['wp' . $sub] = new PlSqlJoin(PlSqlJoin::MODE_LEFT, 'watch_promo', XDB::format('$ME.uid = {?}', substr($key, 5)));
4e7bf1e0
FB
2130 }
2131 }
2132 return $joins;
2133 }
a087cc8d 2134}
8363588b 2135// }}}
3f42a6ad 2136
a087cc8d
FB
2137// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
2138?>