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