Moving to GitHub.
[platal.git] / classes / userfilter.php
CommitLineData
a087cc8d
FB
1<?php
2/***************************************************************************
c441aabe 3 * Copyright (C) 2003-2014 Polytechnique.org *
a087cc8d
FB
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
cd0c2ac4
FB
22require_once dirname(__FILE__) . '/userfilter/conditions.inc.php';
23require_once dirname(__FILE__) . '/userfilter/orders.inc.php';
009b8ab7 24
d865c296
FB
25/***********************************
26 *********************************
27 USER FILTER CLASS
28 *********************************
29 ***********************************/
30
8363588b 31// {{{ class UserFilter
2d83cac9
RB
32/** This class provides a convenient and centralized way of filtering users.
33 *
34 * Usage:
35 * $uf = new UserFilter(new UFC_Blah($x, $y), new UFO_Coin($z, $t));
36 *
37 * Resulting UserFilter can be used to:
38 * - get a list of User objects matching the filter
39 * - get a list of UIDs matching the filter
40 * - get the number of users matching the filter
41 * - check whether a given User matches the filter
42 * - filter a list of User objects depending on whether they match the filter
43 *
44 * Usage for UFC and UFO objects:
45 * A UserFilter will call all private functions named XXXJoins.
46 * These functions must return an array containing the list of join
47 * required by the various UFC and UFO associated to the UserFilter.
48 * Entries in those returned array are of the following form:
49 * 'join_tablealias' => array('join_type', 'joined_table', 'join_criter')
50 * which will be translated into :
51 * join_type JOIN joined_table AS join_tablealias ON (join_criter)
52 * in the final query.
53 *
54 * In the join_criter text, $ME is replaced with 'join_tablealias', $PID with
913a4e90 55 * profile.pid, and $UID with accounts.uid.
2d83cac9
RB
56 *
57 * For each kind of "JOIN" needed, a function named addXXXFilter() should be defined;
58 * its parameter will be used to set various private vars of the UserFilter describing
59 * the required joins ; such a function shall return the "join_tablealias" to use
60 * when referring to the joined table.
61 *
62 * For example, if data from profile_job must be available to filter results,
aab2ffdd 63 * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and
2d83cac9
RB
64 * return 'pj', the short name to use when referring to profile_job; when building
65 * the query, calling the jobJoins function will return an array containing a single
66 * row:
67 * 'pj' => array('left', 'profile_job', '$ME.pid = $UID');
68 *
69 * The 'register_optional' function can be used to generate unique table aliases when
70 * the same table has to be joined several times with different aliases.
71 */
9b8e5fb4 72class UserFilter extends PlFilter
a087cc8d 73{
9b8e5fb4 74 protected $joinMethods = array();
7ca75030 75
61f61261
RB
76 protected $joinMetas = array(
77 '$PID' => 'p.pid',
78 '$UID' => 'a.uid',
9b8e5fb4 79 );
d865c296 80
a087cc8d 81 private $root;
24e08e33 82 private $sort = array();
ccc951d9 83 private $grouper = null;
784745ce 84 private $query = null;
24e08e33 85 private $orderby = null;
784745ce 86
7f26cd69 87 // Store the current 'search' visibility.
22771578
RB
88 private $visibility = null;
89 // If the 'search' visibility should be based on a DB field instead.
90 private $visibility_field = null;
7f26cd69 91
2daf7250
RB
92 private $lastusercount = null;
93 private $lastprofilecount = null;
d865c296 94
24e08e33 95 public function __construct($cond = null, $sort = null)
5dd9d823 96 {
06598c13 97 if (empty($this->joinMethods)) {
d865c296
FB
98 $class = new ReflectionClass('UserFilter');
99 foreach ($class->getMethods() as $method) {
100 $name = $method->getName();
101 if (substr($name, -5) == 'Joins' && $name != 'buildJoins') {
06598c13 102 $this->joinMethods[] = $name;
d865c296
FB
103 }
104 }
105 }
5dd9d823 106 if (!is_null($cond)) {
06598c13 107 if ($cond instanceof PlFilterCondition) {
5dd9d823
FB
108 $this->setCondition($cond);
109 }
110 }
24e08e33 111 if (!is_null($sort)) {
ccc951d9 112 if ($sort instanceof PlFilterOrder) {
24e08e33 113 $this->addSort($sort);
d865c296
FB
114 } else if (is_array($sort)) {
115 foreach ($sort as $s) {
116 $this->addSort($s);
117 }
24e08e33
FB
118 }
119 }
7f26cd69
RB
120
121 // This will set the visibility to the default correct level.
22771578 122 $this->visibility = Visibility::defaultForRead();
7f26cd69
RB
123 }
124
22771578
RB
125 /** Get the SQL condition to filter by visibility level for a field.
126 * This will return a SQL condition which evaluates to True if the given
127 * field display level is available from the current access level.
128 * @param $field Name of the field holding a display level
129 * @return string SQL condition, properly escaped, for that field.
130 */
131 public function getVisibilityConditionForField($field)
132 {
133 if ($this->visibility_field != null) {
134 // Use enum 'bit' arithmetic.
135 // Display levels are ordered as 'hidden, private, ax, public'
136 // Thus ax > private.
137 // The $sub.display_level cell will contain the 'most private' display
138 // level available based on $field. If it is 'ax' and $field is
139 // 'private','ax' <= 'private' is false.
140 $sub = $this->addVisibilityFieldFilter($this->visibility_field);
141 return $sub . '.best_display_level + 0 <= 0 + ' . $field;
142 } else {
143 $sub = $this->addVisibilityAbsoluteFilter($this->visibility->level());
144 return $sub . '.best_display_level + 0 <= 0 + ' . $field;
145 }
e4f1d258
RB
146 }
147
22771578
RB
148 /** Get the SQL condition to filter by a given visibility level.
149 * @param $level One of Visibility::EXPORT_*
150 * @return string A SQL condition, properly escaped, which evaluates to 'true' if the $level can be viewed with the current access level.
151 */
152 public function getVisibilityConditionAbsolute($level)
7f26cd69 153 {
22771578
RB
154 if ($this->visibility_field != null) {
155 // The $sub.display_levels cell will contain allowed display levels
156 // for an access level of $this->visibility_field.
157 $sub = $this->addVisibilityFieldFilter($this->visibility_field);
db492b02 158 return XDB::format('FIND_IN_SET({?}, ' . $sub . '.display_levels)', $level);
22771578
RB
159 } else {
160 if ($this->visibility->isVisible($level)) {
161 return 'TRUE';
162 } else {
163 return 'FALSE';
164 }
165 }
5dd9d823
FB
166 }
167
784745ce
FB
168 private function buildQuery()
169 {
2a93b634
RB
170 // The root condition is built first because some orders need info
171 // available only once all UFC have set their conditions (UFO_Score)
172 if (is_null($this->query)) {
173 $where = $this->root->buildCondition($this);
226626ae
FB
174 $where = str_replace(array_keys($this->joinMetas),
175 $this->joinMetas,
176 $where);
2a93b634 177 }
d865c296
FB
178 if (is_null($this->orderby)) {
179 $orders = array();
180 foreach ($this->sort as $sort) {
181 $orders = array_merge($orders, $sort->buildSort($this));
182 }
183 if (count($orders) == 0) {
184 $this->orderby = '';
185 } else {
186 $this->orderby = 'ORDER BY ' . implode(', ', $orders);
187 }
226626ae
FB
188 $this->orderby = str_replace(array_keys($this->joinMetas),
189 $this->joinMetas,
190 $this->orderby);
d865c296 191 }
784745ce 192 if (is_null($this->query)) {
2a93b634 193 if ($this->with_accounts) {
b8dcf62d
RB
194 $from = 'accounts AS a';
195 } else {
196 $this->requireProfiles();
197 $from = 'profiles AS p';
198 }
f7ea7450 199 $joins = $this->buildJoins();
b8dcf62d 200 $this->query = 'FROM ' . $from . '
784745ce
FB
201 ' . $joins . '
202 WHERE (' . $where . ')';
203 }
204 }
205
ccc951d9
RB
206 public function hasGroups()
207 {
208 return $this->grouper != null;
209 }
210
211 public function getGroups()
212 {
213 return $this->getUIDGroups();
214 }
215
216 public function getUIDGroups()
217 {
218 $this->requireAccounts();
219 $this->buildQuery();
220 $token = $this->grouper->getGroupToken($this);
221
59db57ab
FB
222 $groups = XDB::rawFetchAllRow('SELECT ' . $token . ', COUNT(a.uid)
223 ' . $this->query . '
224 GROUP BY ' . $token,
225 0);
ccc951d9
RB
226 return $groups;
227 }
228
229 public function getPIDGroups()
230 {
231 $this->requireProfiles();
232 $this->buildQuery();
233 $token = $this->grouper->getGroupToken($this);
234
59db57ab
FB
235 $groups = XDB::rawFetchAllRow('SELECT ' . $token . ', COUNT(p.pid)
236 ' . $this->query . '
237 GROUP BY ' . $token,
238 0);
ccc951d9
RB
239 return $groups;
240 }
241
26ba053e 242 private function getUIDList($uids = null, PlLimit $limit)
d865c296 243 {
b8dcf62d 244 $this->requireAccounts();
d865c296 245 $this->buildQuery();
7ca75030 246 $lim = $limit->getSql();
d865c296 247 $cond = '';
45b20ca0 248 if (!empty($uids)) {
bde68f05 249 $cond = XDB::format(' AND a.uid IN {?}', $uids);
d865c296 250 }
59db57ab
FB
251 $fetched = XDB::rawFetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid
252 ' . $this->query . $cond . '
253 GROUP BY a.uid
254 ' . $this->orderby . '
255 ' . $lim);
2daf7250 256 $this->lastusercount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
d865c296
FB
257 return $fetched;
258 }
259
26ba053e 260 private function getPIDList($pids = null, PlLimit $limit)
043b104b
RB
261 {
262 $this->requireProfiles();
263 $this->buildQuery();
264 $lim = $limit->getSql();
265 $cond = '';
266 if (!is_null($pids)) {
bde68f05 267 $cond = XDB::format(' AND p.pid IN {?}', $pids);
043b104b 268 }
59db57ab
FB
269 $fetched = XDB::rawFetchColumn('SELECT SQL_CALC_FOUND_ROWS p.pid
270 ' . $this->query . $cond . '
271 GROUP BY p.pid
272 ' . $this->orderby . '
273 ' . $lim);
2daf7250 274 $this->lastprofilecount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()');
043b104b
RB
275 return $fetched;
276 }
277
434570c4
FB
278 private static function defaultLimit($limit) {
279 if ($limit == null) {
280 return new PlLimit();
281 } else {
282 return $limit;
283 }
284 }
285
a087cc8d
FB
286 /** Check that the user match the given rule.
287 */
26ba053e 288 public function checkUser(PlUser $user)
a087cc8d 289 {
b8dcf62d 290 $this->requireAccounts();
784745ce 291 $this->buildQuery();
59db57ab
FB
292 $count = (int)XDB::rawFetchOneCell('SELECT COUNT(*)
293 ' . $this->query
294 . XDB::format(' AND a.uid = {?}', $user->id()));
784745ce 295 return $count == 1;
a087cc8d
FB
296 }
297
043b104b
RB
298 /** Check that the profile match the given rule.
299 */
26ba053e 300 public function checkProfile(Profile $profile)
043b104b
RB
301 {
302 $this->requireProfiles();
303 $this->buildQuery();
59db57ab
FB
304 $count = (int)XDB::rawFetchOneCell('SELECT COUNT(*)
305 ' . $this->query
306 . XDB::format(' AND p.pid = {?}', $profile->id()));
043b104b
RB
307 return $count == 1;
308 }
309
310 /** Default filter is on users
a087cc8d 311 */
434570c4 312 public function filter(array $users, $limit = null)
a087cc8d 313 {
434570c4 314 return $this->filterUsers($users, self::defaultLimit($limit));
043b104b
RB
315 }
316
317 /** Filter a list of users to extract the users matching the rule.
318 */
434570c4 319 public function filterUsers(array $users, $limit = null)
043b104b 320 {
434570c4 321 $limit = self::defaultLimit($limit);
b8dcf62d 322 $this->requireAccounts();
4927ee54
FB
323 $this->buildQuery();
324 $table = array();
325 $uids = array();
326 foreach ($users as $user) {
07eb5b0e
FB
327 if ($user instanceof PlUser) {
328 $uid = $user->id();
329 } else {
330 $uid = $user;
331 }
332 $uids[] = $uid;
333 $table[$uid] = $user;
4927ee54 334 }
7ca75030 335 $fetched = $this->getUIDList($uids, $limit);
a087cc8d 336 $output = array();
4927ee54
FB
337 foreach ($fetched as $uid) {
338 $output[] = $table[$uid];
a087cc8d
FB
339 }
340 return $output;
341 }
342
043b104b
RB
343 /** Filter a list of profiles to extract the users matching the rule.
344 */
434570c4 345 public function filterProfiles(array $profiles, $limit = null)
043b104b 346 {
434570c4 347 $limit = self::defaultLimit($limit);
043b104b
RB
348 $this->requireProfiles();
349 $this->buildQuery();
350 $table = array();
351 $pids = array();
352 foreach ($profiles as $profile) {
353 if ($profile instanceof Profile) {
354 $pid = $profile->id();
355 } else {
356 $pid = $profile;
357 }
358 $pids[] = $pid;
359 $table[$pid] = $profile;
360 }
361 $fetched = $this->getPIDList($pids, $limit);
362 $output = array();
363 foreach ($fetched as $pid) {
364 $output[] = $table[$pid];
365 }
366 return $output;
367 }
368
434570c4 369 public function getUIDs($limit = null)
7ca75030 370 {
833a6e86
FB
371 $limit = self::defaultLimit($limit);
372 return $this->getUIDList(null, $limit);
7ca75030
RB
373 }
374
ad27b22e
FB
375 public function getUID($pos = 0)
376 {
983f3864 377 $uids =$this->getUIDList(null, new PlLimit(1, $pos));
ad27b22e
FB
378 if (count($uids) == 0) {
379 return null;
380 } else {
381 return $uids[0];
382 }
383 }
384
434570c4 385 public function getPIDs($limit = null)
043b104b 386 {
833a6e86
FB
387 $limit = self::defaultLimit($limit);
388 return $this->getPIDList(null, $limit);
043b104b
RB
389 }
390
ad27b22e
FB
391 public function getPID($pos = 0)
392 {
983f3864 393 $pids =$this->getPIDList(null, new PlLimit(1, $pos));
ad27b22e
FB
394 if (count($pids) == 0) {
395 return null;
396 } else {
397 return $pids[0];
398 }
399 }
400
434570c4 401 public function getUsers($limit = null)
4927ee54 402 {
7ca75030 403 return User::getBulkUsersWithUIDs($this->getUIDs($limit));
d865c296
FB
404 }
405
ad27b22e
FB
406 public function getUser($pos = 0)
407 {
408 $uid = $this->getUID($pos);
409 if ($uid == null) {
410 return null;
411 } else {
412 return User::getWithUID($uid);
413 }
414 }
415
0d906109
RB
416 public function iterUsers($limit = null)
417 {
418 return User::iterOverUIDs($this->getUIDs($limit));
419 }
420
22771578 421 public function getProfiles($limit = null, $fields = 0x0000, $visibility = null)
043b104b 422 {
00f83317 423 return Profile::getBulkProfilesWithPIDs($this->getPIDs($limit), $fields, $visibility);
043b104b
RB
424 }
425
22771578 426 public function getProfile($pos = 0, $fields = 0x0000, $visibility = null)
ad27b22e
FB
427 {
428 $pid = $this->getPID($pos);
429 if ($pid == null) {
430 return null;
431 } else {
00f83317 432 return Profile::get($pid, $fields, $visibility);
ad27b22e
FB
433 }
434 }
435
22771578 436 public function iterProfiles($limit = null, $fields = 0x0000, $visibility = null)
0d906109 437 {
00f83317 438 return Profile::iterOverPIDs($this->getPIDs($limit), true, $fields, $visibility);
0d906109
RB
439 }
440
434570c4 441 public function get($limit = null)
d865c296 442 {
7ca75030 443 return $this->getUsers($limit);
4927ee54
FB
444 }
445
d5fd47bf
SJ
446 public function getIds($limit = null)
447 {
448 return $this->getUIDs();
449 }
aaf70eb8 450
d865c296 451 public function getTotalCount()
4927ee54 452 {
2daf7250
RB
453 return $this->getTotalUserCount();
454 }
455
456 public function getTotalUserCount()
457 {
458 if (is_null($this->lastusercount)) {
459 $this->requireAccounts();
aa21c568 460 $this->buildQuery();
59db57ab 461 return (int)XDB::rawFetchOneCell('SELECT COUNT(DISTINCT a.uid)
2daf7250
RB
462 ' . $this->query);
463 } else {
464 return $this->lastusercount;
465 }
466 }
467
468 public function getTotalProfileCount()
469 {
470 if (is_null($this->lastprofilecount)) {
471 $this->requireProfiles();
472 $this->buildQuery();
59db57ab 473 return (int)XDB::rawFetchOneCell('SELECT COUNT(DISTINCT p.pid)
7e735012 474 ' . $this->query);
38c6fe96 475 } else {
2daf7250 476 return $this->lastprofilecount;
38c6fe96 477 }
4927ee54
FB
478 }
479
93ded2f4 480 public function setCondition(PlFilterCondition $cond)
a087cc8d
FB
481 {
482 $this->root =& $cond;
784745ce 483 $this->query = null;
a087cc8d
FB
484 }
485
93ded2f4 486 public function addSort(PlFilterOrder $sort)
24e08e33 487 {
ccc951d9
RB
488 if (count($this->sort) == 0 && $sort instanceof PlFilterGroupableOrder)
489 {
490 $this->grouper = $sort;
491 }
d865c296
FB
492 $this->sort[] = $sort;
493 $this->orderby = null;
24e08e33
FB
494 }
495
30eedabf
FB
496 public function export()
497 {
b3deda78 498 $export = array('conditions' => $this->root->export());
30eedabf 499 if (!empty($this->sort)) {
b3deda78 500 $export['sorts'] = array();
30eedabf 501 foreach ($this->sort as $sort) {
b3deda78 502 $export['sorts'][] = $sort->export();
30eedabf
FB
503 }
504 }
505 return $export;
506 }
507
b3deda78
FB
508 public function exportConditions()
509 {
510 return $this->root->export();
511 }
512
513 public static function fromExport(array $export)
514 {
515 $export = new PlDict($export);
516 if (!$export->has('conditions')) {
517 throw new Exception("Cannot build a user filter without conditions");
518 }
519 $cond = UserFilterCondition::fromExport($export->v('conditions'));
520 $sorts = null;
521 if ($export->has('sorts')) {
522 $sorts = array();
523 foreach ($export->v('sorts') as $sort) {
524 $sorts[] = UserFilterOrder::fromExport($sort);
525 }
526 }
527 return new UserFilter($cond, $sorts);
528 }
529
530 public static function fromJSon($json)
531 {
532 $export = json_decode($json, true);
533 if (is_null($export)) {
534 throw new Exception("Invalid json: $json");
535 }
536 return self::fromExport($json);
537 }
538
539 public static function fromExportedConditions(array $export)
540 {
541 $cond = UserFilterCondition::fromExport($export);
542 return new UserFilter($cond);
543 }
544
545 public static function fromJSonConditions($json)
546 {
547 $export = json_decode($json, true);
548 if (is_null($export)) {
549 throw new Exception("Invalid json: $json");
550 }
551 return self::fromExportedConditions($json);
552 }
553
a087cc8d
FB
554 static public function getLegacy($promo_min, $promo_max)
555 {
a087cc8d 556 if ($promo_min != 0) {
784745ce 557 $min = new UFC_Promo('>=', self::GRADE_ING, intval($promo_min));
5dd9d823 558 } else {
88c31faf 559 $min = new PFC_True();
a087cc8d 560 }
a087cc8d 561 if ($promo_max != 0) {
784745ce 562 $max = new UFC_Promo('<=', self::GRADE_ING, intval($promo_max));
a087cc8d 563 } else {
88c31faf 564 $max = new PFC_True();
a087cc8d 565 }
9b8e5fb4 566 return new UserFilter(new PFC_And($min, $max));
a087cc8d 567 }
784745ce 568
07eb5b0e
FB
569 static public function sortByName()
570 {
3e6ab778 571 return array(new UFO_Name());
07eb5b0e
FB
572 }
573
574 static public function sortByPromo()
575 {
3e6ab778 576 return array(new UFO_Promo(), new UFO_Name());
07eb5b0e
FB
577 }
578
aa21c568
FB
579 static private function getDBSuffix($string)
580 {
2d6329a2
FB
581 if (is_array($string)) {
582 if (count($string) == 1) {
583 return self::getDBSuffix(array_pop($string));
584 }
585 return md5(implode('|', $string));
586 } else {
587 return preg_replace('/[^a-z0-9]/i', '', $string);
588 }
aa21c568
FB
589 }
590
591
2d83cac9
RB
592 /** Stores a new (and unique) table alias in the &$table table
593 * @param &$table Array in which the table alias must be stored
594 * @param $val Value which will then be used to build the join
595 * @return Name of the newly created alias
596 */
aa21c568
FB
597 private $option = 0;
598 private function register_optional(array &$table, $val)
599 {
600 if (is_null($val)) {
601 $sub = $this->option++;
602 $index = null;
603 } else {
604 $sub = self::getDBSuffix($val);
605 $index = $val;
606 }
607 $sub = '_' . $sub;
608 $table[$sub] = $index;
609 return $sub;
610 }
784745ce 611
b8dcf62d
RB
612 /** PROFILE VS ACCOUNT
613 */
f7ea7450
RB
614 private $with_profiles = false;
615 private $with_accounts = false;
b8dcf62d
RB
616 public function requireAccounts()
617 {
618 $this->with_accounts = true;
619 }
620
a9ef52c9
RB
621 public function accountsRequired()
622 {
623 return $this->with_accounts;
624 }
625
b8dcf62d
RB
626 public function requireProfiles()
627 {
628 $this->with_profiles = true;
629 }
630
a9ef52c9
RB
631 public function profilesRequired()
632 {
633 return $this->with_profiles;
634 }
635
b8dcf62d
RB
636 protected function accountJoins()
637 {
638 $joins = array();
2a93b634 639 if ($this->with_profiles && $this->with_accounts) {
5c412626
FB
640 $joins['ap'] = PlSqlJoin::left('account_profiles', '$ME.uid = $UID AND FIND_IN_SET(\'owner\', ap.perms)');
641 $joins['p'] = PlSqlJoin::left('profiles', '$PID = ap.pid');
b8dcf62d
RB
642 }
643 return $joins;
644 }
645
1eabd2a4
FB
646 /** PERMISSIONS
647 */
648 private $at = false;
649 public function requirePerms()
650 {
651 $this->requireAccounts();
652 $this->at = true;
653 return 'at';
654 }
655
656 protected function permJoins()
657 {
658 if ($this->at) {
659 return array('at' => PlSqlJoin::left('account_types', '$ME.type = a.type'));
660 } else {
661 return array();
662 }
663 }
664
d865c296
FB
665 /** DISPLAY
666 */
38c6fe96 667 const DISPLAY = 'display';
d865c296
FB
668 private $pd = false;
669 public function addDisplayFilter()
670 {
b8dcf62d 671 $this->requireProfiles();
d865c296
FB
672 $this->pd = true;
673 return '';
674 }
675
9b8e5fb4 676 protected function displayJoins()
d865c296
FB
677 {
678 if ($this->pd) {
5c412626 679 return array('pd' => PlSqlJoin::left('profile_display', '$ME.pid = $PID'));
d865c296
FB
680 } else {
681 return array();
682 }
683 }
684
f73a4f1b
RB
685 /** LOGGER
686 */
687
688 private $with_logger = false;
689 public function addLoggerFilter()
690 {
691 $this->with_logger = true;
692 $this->requireAccounts();
693 return 'ls';
694 }
695 protected function loggerJoins()
696 {
697 $joins = array();
698 if ($this->with_logger) {
5c412626 699 $joins['ls'] = PlSqlJoin::left('log_sessions', '$ME.uid = $UID');
f73a4f1b
RB
700 }
701 return $joins;
702 }
703
40585144
RB
704 /** NAMETOKENS
705 */
2a93b634
RB
706 private $name_tokens = array();
707 private $nb_tokens = 0;
708
709 public function addNameTokensFilter($token)
40585144
RB
710 {
711 $this->requireProfiles();
2a93b634
RB
712 $sub = 'sn' . (1 + $this->nb_tokens);
713 $this->nb_tokens++;
714 $this->name_tokens[$sub] = $token;
715 return $sub;
40585144
RB
716 }
717
718 protected function nameTokensJoins()
719 {
f7ea7450 720 /* We don't return joins, since with_sn forces the SELECT to run on search_name first */
2a93b634
RB
721 $joins = array();
722 foreach ($this->name_tokens as $sub => $token) {
723 $joins[$sub] = PlSqlJoin::left('search_name', '$ME.pid = $PID');
40585144 724 }
2a93b634
RB
725 return $joins;
726 }
727
728 public function getNameTokens()
729 {
730 return $this->name_tokens;
40585144
RB
731 }
732
a7f8e48a
RB
733 /** NATIONALITY
734 */
735
736 private $with_nat = false;
737 public function addNationalityFilter()
738 {
739 $this->with_nat = true;
740 return 'ngc';
741 }
742
743 protected function nationalityJoins()
744 {
745 $joins = array();
746 if ($this->with_nat) {
5c412626 747 $joins['ngc'] = PlSqlJoin::left('geoloc_countries', '$ME.iso_3166_1_a2 = p.nationality1 OR $ME.iso_3166_1_a2 = p.nationality2 OR $ME.iso_3166_1_a2 = p.nationality3');
a7f8e48a
RB
748 }
749 return $joins;
750 }
751
784745ce
FB
752 /** EDUCATION
753 */
9a6abd1f
SJ
754 const GRADE_ING = Profile::DEGREE_X;
755 const GRADE_PHD = Profile::DEGREE_D;
756 const GRADE_MST = Profile::DEGREE_M;
784745ce
FB
757 static public function isGrade($grade)
758 {
93c2f133 759 return ($grade !== 0) && ($grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST);
784745ce
FB
760 }
761
762 static public function assertGrade($grade)
763 {
764 if (!self::isGrade($grade)) {
ad27b22e 765 Platal::page()->killError("Diplôme non valide: $grade");
784745ce
FB
766 }
767 }
768
d865c296
FB
769 static public function promoYear($grade)
770 {
771 // XXX: Definition of promotion for phds and masters might change in near future.
772 return ($grade == UserFilter::GRADE_ING) ? 'entry_year' : 'grad_year';
773 }
774
784745ce
FB
775 private $pepe = array();
776 private $with_pee = false;
784745ce
FB
777 public function addEducationFilter($x = false, $grade = null)
778 {
b8dcf62d 779 $this->requireProfiles();
784745ce 780 if (!$x) {
aa21c568
FB
781 $index = $this->option;
782 $sub = $this->option++;
784745ce
FB
783 } else {
784 self::assertGrade($grade);
785 $index = $grade;
786 $sub = $grade[0];
787 $this->with_pee = true;
788 }
789 $sub = '_' . $sub;
790 $this->pepe[$index] = $sub;
791 return $sub;
792 }
793
9b8e5fb4 794 protected function educationJoins()
784745ce
FB
795 {
796 $joins = array();
797 if ($this->with_pee) {
5c412626 798 $joins['pee'] = PlSqlJoin::inner('profile_education_enum', 'pee.abbreviation = \'X\'');
784745ce
FB
799 }
800 foreach ($this->pepe as $grade => $sub) {
801 if ($this->isGrade($grade)) {
5c412626 802 $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.eduid = pee.id AND $ME.pid = $PID');
9a6abd1f 803 $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid AND $ME.degree LIKE {?}', $grade);
784745ce 804 } else {
5c412626
FB
805 $joins['pe' . $sub] = PlSqlJoin::left('profile_education', '$ME.pid = $PID');
806 $joins['pee' . $sub] = PlSqlJoin::inner('profile_education_enum', '$ME.id = pe' . $sub . '.eduid');
807 $joins['pede' . $sub] = PlSqlJoin::inner('profile_education_degree_enum', '$ME.id = pe' . $sub . '.degreeid');
784745ce
FB
808 }
809 }
810 return $joins;
811 }
4927ee54
FB
812
813
814 /** GROUPS
815 */
816 private $gpm = array();
4927ee54
FB
817 public function addGroupFilter($group = null)
818 {
b8dcf62d 819 $this->requireAccounts();
4927ee54 820 if (!is_null($group)) {
4aae4d2c 821 if (is_int($group) || ctype_digit($group)) {
4927ee54
FB
822 $index = $sub = $group;
823 } else {
824 $index = $group;
aa21c568 825 $sub = self::getDBSuffix($group);
4927ee54
FB
826 }
827 } else {
aa21c568 828 $sub = 'group_' . $this->option++;
4927ee54
FB
829 $index = null;
830 }
831 $sub = '_' . $sub;
832 $this->gpm[$sub] = $index;
833 return $sub;
834 }
835
486bc076
SJ
836 private $gpfm = array();
837 public function addGroupFormerMemberFilter()
838 {
839 $this->requireAccounts();
840 $sub = '_' . $this->option++;
841 $this->gpfm[] = $sub;
842 return $sub;
843 }
844
9b8e5fb4 845 protected function groupJoins()
4927ee54
FB
846 {
847 $joins = array();
848 foreach ($this->gpm as $sub => $key) {
849 if (is_null($key)) {
5c412626
FB
850 $joins['gpa' . $sub] = PlSqlJoin::inner('groups');
851 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4aae4d2c 852 } else if (is_int($key) || ctype_digit($key)) {
5c412626 853 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = ' . $key);
4927ee54 854 } else {
5c412626
FB
855 $joins['gpa' . $sub] = PlSqlJoin::inner('groups', '$ME.diminutif = {?}', $key);
856 $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id');
4927ee54
FB
857 }
858 }
486bc076
SJ
859 foreach ($this->gpfm as $sub) {
860 $joins['gpfm' . $sub] = PlSqlJoin::left('group_former_members', '$ME.uid = $UID');
861 }
4927ee54 862 return $joins;
0fb3713c
RB
863 }
864
57a4162e
RB
865 /** NLS
866 */
867 private $nls = array();
868 public function addNewsLetterFilter($nlid)
869 {
870 $this->requireAccounts();
871 $sub = 'nl_' . $nlid;
872 $this->nls[$nlid] = $sub;
873 return $sub;
874 }
875
876 protected function newsLetterJoins()
877 {
878 $joins = array();
879 foreach ($this->nls as $key => $sub) {
880 $joins[$sub] = PlSqlJoin::left('newsletter_ins', '$ME.nlid = {?} AND $ME.uid = $UID', $key);
881 }
882 return $joins;
883 }
884
0fb3713c
RB
885 /** BINETS
886 */
887
a7f8e48a
RB
888 private $with_bi = false;
889 private $with_bd = false;
d7ddf29b 890 public function addBinetsFilter($with_enum = false)
0fb3713c
RB
891 {
892 $this->requireProfiles();
a7f8e48a
RB
893 $this->with_bi = true;
894 if ($with_enum) {
895 $this->with_bd = true;
896 return 'bd';
897 } else {
898 return 'bi';
899 }
0fb3713c
RB
900 }
901
902 protected function binetsJoins()
903 {
904 $joins = array();
a7f8e48a 905 if ($this->with_bi) {
5c412626 906 $joins['bi'] = PlSqlJoin::left('profile_binets', '$ME.pid = $PID');
0fb3713c 907 }
a7f8e48a 908 if ($this->with_bd) {
5c412626 909 $joins['bd'] = PlSqlJoin::left('profile_binet_enum', '$ME.id = bi.binet_id');
a7f8e48a 910 }
0fb3713c 911 return $joins;
4927ee54 912 }
aa21c568
FB
913
914 /** EMAILS
915 */
e338c7e8
SJ
916 private $ra = array();
917 /** Allows filtering by redirection.
918 * @param $email If null, enable a left join on the email redirection table
919 * (email_redirect_account); otherwise, perform a left join on users having
920 * that email as a redirection.
921 * @return Suffix to use to access the adequate table.
922 */
aa21c568
FB
923 public function addEmailRedirectFilter($email = null)
924 {
b8dcf62d 925 $this->requireAccounts();
e338c7e8
SJ
926 return $this->register_optional($this->ra, $email);
927 }
928
929 const ALIAS_BEST = 'bestalias';
930 const ALIAS_FORLIFE = 'forlife';
931 const ALIAS_AUXILIARY = 'alias_aux';
932 private $sa = array();
933 /** Allows filtering by source email.
934 * @param $email If null, enable a left join on the email source table
935 * (email_source_account); otherwise, perform a left join on users having
936 * that email as a source email.
937 * @return Suffix to use to access the adequate table.
938 */
0b42c25f 939 public function addAliasFilter($email = null)
aa21c568 940 {
b8dcf62d 941 $this->requireAccounts();
e338c7e8 942 return $this->register_optional($this->sa, $email);
aa21c568
FB
943 }
944
0702af29
SJ
945 private $with_rf = false;
946 /** Allows filtering by active redirection.
947 * @return Suffix to use to access the adequate table.
948 */
949 public function addActiveEmailRedirectFilter($email = null)
950 {
951 $this->requireAccounts();
952 $this->with_rf = true;
953 }
954
9b8e5fb4 955 protected function emailJoins()
aa21c568
FB
956 {
957 global $globals;
958 $joins = array();
e338c7e8
SJ
959 foreach ($this->ra as $sub => $redirections) {
960 if (is_null($redirections)) {
961 $joins['ra' . $sub] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\'');
aa21c568 962 } else {
e338c7e8
SJ
963 if (!is_array($redirections)) {
964 $key = array($redirections);
2d6329a2 965 }
3b5d24d2 966 $joins['ra' . $sub] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\'
e338c7e8 967 AND $ME.redirect IN {?}', $redirections);
aa21c568
FB
968 }
969 }
e338c7e8
SJ
970 foreach ($this->sa as $sub => $emails) {
971 if (is_null($emails)) {
972 $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID');
ea02f4ae 973 } else if ($sub == self::ALIAS_BEST) {
e338c7e8 974 $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND FIND_IN_SET(\'bestalias\', $ME.flags)');
ea02f4ae 975 } else if ($sub == self::ALIAS_FORLIFE) {
e338c7e8 976 $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.type = \'forlife\'');
ea02f4ae 977 } else if ($sub == self::ALIAS_AUXILIARY) {
e338c7e8 978 $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.type = \'alias_aux\'');
aa21c568 979 } else {
e338c7e8
SJ
980 if (!is_array($emails)) {
981 $key = array($emails);
2d6329a2 982 }
e338c7e8 983 $joins['sa' . $sub] = PlSqlJoin::left('email_source_account', '$ME.uid = $UID AND $ME.email IN {?}', $emails);
aa21c568 984 }
57a4162e 985 }
0702af29
SJ
986 if ($this->with_rf) {
987 $joins['rf'] = PlSqlJoin::left('email_redirect_account', '$ME.uid = $UID AND $ME.type != \'imap\' AND $ME.flags = \'active\'');;
988 }
aa21c568
FB
989 return $joins;
990 }
3f42a6ad
FB
991
992
c4b24511
RB
993 /** ADDRESSES
994 */
3a2985f9
SJ
995 private $types = array();
996 public function addAddressFilter($type)
c4b24511 997 {
b8dcf62d 998 $this->requireProfiles();
036d1637 999 $this->with_pa = true;
2b9ca54d 1000
3a2985f9
SJ
1001 $sub = '_' . $this->option++;
1002 $this->types[$type] = $sub;
1003 return $sub;
2b9ca54d
RB
1004 }
1005
9b8e5fb4 1006 protected function addressJoins()
c4b24511
RB
1007 {
1008 $joins = array();
3a2985f9
SJ
1009 foreach ($this->types as $type => $sub) {
1010 $joins['pa' . $sub] = PlSqlJoin::inner('profile_addresses', '$ME.pid = $PID');
1011 $joins['pac' . $sub] = PlSqlJoin::inner('profile_addresses_components',
1012 '$ME.pid = pa' . $sub . '.pid AND $ME.jobid = pa' . $sub . '.jobid AND $ME.groupid = pa' . $sub . '.groupid AND $ME.type = pa' . $sub . '.type AND $ME.id = pa' . $sub . '.id');
1013 $joins['pace' . $sub] = PlSqlJoin::inner('profile_addresses_components_enum',
1014 '$ME.id = pac' . $sub . '.component_id AND FIND_IN_SET({?}, $ME.types)', $type);
2b9ca54d 1015 }
3a2985f9 1016
c4b24511
RB
1017 return $joins;
1018 }
1019
1020
4083b126
RB
1021 /** CORPS
1022 */
1023
1024 private $pc = false;
1025 private $pce = array();
1026 private $pcr = false;
1027 public function addCorpsFilter($type)
1028 {
b8dcf62d 1029 $this->requireProfiles();
4083b126
RB
1030 $this->pc = true;
1031 if ($type == UFC_Corps::CURRENT) {
00f25ab1 1032 $this->pce['pcec'] = 'current_corpsid';
4083b126
RB
1033 return 'pcec';
1034 } else if ($type == UFC_Corps::ORIGIN) {
00f25ab1 1035 $this->pce['pceo'] = 'original_corpsid';
4083b126
RB
1036 return 'pceo';
1037 }
1038 }
1039
1040 public function addCorpsRankFilter()
1041 {
b8dcf62d 1042 $this->requireProfiles();
4083b126
RB
1043 $this->pc = true;
1044 $this->pcr = true;
1045 return 'pcr';
1046 }
1047
9b8e5fb4 1048 protected function corpsJoins()
4083b126
RB
1049 {
1050 $joins = array();
1051 if ($this->pc) {
5c412626 1052 $joins['pc'] = PlSqlJoin::left('profile_corps', '$ME.pid = $PID');
4083b126
RB
1053 }
1054 if ($this->pcr) {
5c412626 1055 $joins['pcr'] = PlSqlJoin::left('profile_corps_rank_enum', '$ME.id = pc.rankid');
4083b126
RB
1056 }
1057 foreach($this->pce as $sub => $field) {
5c412626 1058 $joins[$sub] = PlSqlJoin::left('profile_corps_enum', '$ME.id = pc.' . $field);
4083b126
RB
1059 }
1060 return $joins;
1061 }
1062
6a99c3ac
RB
1063 /** JOBS
1064 */
1065
da40b2a4
SJ
1066 const JOB_USERDEFINED = 0x0001;
1067 const JOB_CV = 0x0002;
1068 const JOB_ANY = 0x0003;
6a99c3ac
RB
1069
1070 /** Joins :
1071 * pj => profile_job
1072 * pje => profile_job_enum
3ac45f10 1073 * pjt => profile_job_terms
6a99c3ac 1074 */
da40b2a4 1075 private $with_pj = false;
6a99c3ac 1076 private $with_pje = false;
3ac45f10 1077 private $with_pjt = 0;
6a99c3ac
RB
1078
1079 public function addJobFilter()
1080 {
b8dcf62d 1081 $this->requireProfiles();
6a99c3ac
RB
1082 $this->with_pj = true;
1083 return 'pj';
1084 }
1085
1086 public function addJobCompanyFilter()
1087 {
1088 $this->addJobFilter();
1089 $this->with_pje = true;
1090 return 'pje';
1091 }
1092
3ac45f10
PC
1093 /**
1094 * Adds a filter on job terms of profile.
1095 * @param $nb the number of job terms to use
1096 * @return an array of the fields to filter (one for each term).
3ac45f10
PC
1097 */
1098 public function addJobTermsFilter($nb = 1)
1099 {
1100 $this->with_pjt = $nb;
1101 $jobtermstable = array();
1102 for ($i = 1; $i <= $nb; ++$i) {
4ec03752 1103 $jobtermstable[] = 'pjtr_'.$i;
3ac45f10
PC
1104 }
1105 return $jobtermstable;
1106 }
1107
9b8e5fb4 1108 protected function jobJoins()
6a99c3ac
RB
1109 {
1110 $joins = array();
1111 if ($this->with_pj) {
5c412626 1112 $joins['pj'] = PlSqlJoin::left('profile_job', '$ME.pid = $PID');
6a99c3ac
RB
1113 }
1114 if ($this->with_pje) {
5c412626 1115 $joins['pje'] = PlSqlJoin::left('profile_job_enum', '$ME.id = pj.jobid');
6a99c3ac 1116 }
3ac45f10
PC
1117 if ($this->with_pjt > 0) {
1118 for ($i = 1; $i <= $this->with_pjt; ++$i) {
1119 $joins['pjt_'.$i] = PlSqlJoin::left('profile_job_term', '$ME.pid = $PID');
1120 $joins['pjtr_'.$i] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pjt_'.$i.'.jtid');
1121 }
1122 }
6a99c3ac
RB
1123 return $joins;
1124 }
1125
0a2e9c74
RB
1126 /** NETWORKING
1127 */
1128
1129 private $with_pnw = false;
1130 public function addNetworkingFilter()
1131 {
b8dcf62d 1132 $this->requireAccounts();
0a2e9c74
RB
1133 $this->with_pnw = true;
1134 return 'pnw';
1135 }
1136
9b8e5fb4 1137 protected function networkingJoins()
0a2e9c74
RB
1138 {
1139 $joins = array();
1140 if ($this->with_pnw) {
5c412626 1141 $joins['pnw'] = PlSqlJoin::left('profile_networking', '$ME.pid = $PID');
0a2e9c74
RB
1142 }
1143 return $joins;
1144 }
1145
6d62969e
RB
1146 /** PHONE
1147 */
1148
2d83cac9 1149 private $with_ptel = false;
6d62969e
RB
1150
1151 public function addPhoneFilter()
1152 {
b8dcf62d 1153 $this->requireAccounts();
2d83cac9 1154 $this->with_ptel = true;
6d62969e
RB
1155 return 'ptel';
1156 }
1157
9b8e5fb4 1158 protected function phoneJoins()
6d62969e
RB
1159 {
1160 $joins = array();
2d83cac9 1161 if ($this->with_ptel) {
5c412626 1162 $joins['ptel'] = PlSqlJoin::left('profile_phones', '$ME.pid = $PID');
6d62969e
RB
1163 }
1164 return $joins;
1165 }
1166
ceb512d2
RB
1167 /** MEDALS
1168 */
1169
2d83cac9 1170 private $with_pmed = false;
ceb512d2
RB
1171 public function addMedalFilter()
1172 {
b8dcf62d 1173 $this->requireProfiles();
2d83cac9 1174 $this->with_pmed = true;
ceb512d2
RB
1175 return 'pmed';
1176 }
1177
9b8e5fb4 1178 protected function medalJoins()
ceb512d2
RB
1179 {
1180 $joins = array();
2d83cac9 1181 if ($this->with_pmed) {
5c412626 1182 $joins['pmed'] = PlSqlJoin::left('profile_medals', '$ME.pid = $PID');
ceb512d2
RB
1183 }
1184 return $joins;
1185 }
1186
49707d3b
RB
1187 /** DELTATEN
1188 */
1189 private $dts = array();
1190 const DELTATEN = 1;
1191 const DELTATEN_MESSAGE = 2;
1192 // TODO: terms
1193
1194 public function addDeltaTenFilter($type)
1195 {
1196 $this->requireProfiles();
1197 switch ($type) {
1198 case self::DELTATEN:
1199 $this->dts['pdt'] = 'profile_deltaten';
1200 return 'pdt';
1201 case self::DELTATEN_MESSAGE:
1202 $this->dts['pdtm'] = 'profile_deltaten';
1203 return 'pdtm';
1204 default:
1205 Platal::page()->killError("Undefined DeltaTen filter.");
1206 }
1207 }
1208
1209 protected function deltatenJoins()
1210 {
1211 $joins = array();
1212 foreach ($this->dts as $sub => $tab) {
1213 $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID');
1214 }
1215 return $joins;
1216 }
1217
671b7073
RB
1218 /** MENTORING
1219 */
1220
1221 private $pms = array();
459e6f81 1222 private $mjtr = false;
96f01fba
RB
1223 const MENTOR = 1;
1224 const MENTOR_EXPERTISE = 2;
1225 const MENTOR_COUNTRY = 3;
da40b2a4 1226 const MENTOR_TERM = 4;
671b7073
RB
1227
1228 public function addMentorFilter($type)
1229 {
49707d3b 1230 $this->requireProfiles();
671b7073 1231 switch($type) {
96f01fba
RB
1232 case self::MENTOR:
1233 $this->pms['pm'] = 'profile_mentor';
1234 return 'pm';
4a93c3a3
RB
1235 case self::MENTOR_EXPERTISE:
1236 $this->pms['pme'] = 'profile_mentor';
671b7073 1237 return 'pme';
4a93c3a3
RB
1238 case self::MENTOR_COUNTRY:
1239 $this->pms['pmc'] = 'profile_mentor_country';
671b7073 1240 return 'pmc';
459e6f81
PC
1241 case self::MENTOR_TERM:
1242 $this->pms['pmt'] = 'profile_mentor_term';
1243 $this->mjtr = true;
1244 return 'mjtr';
671b7073 1245 default:
5d2e55c7 1246 Platal::page()->killError("Undefined mentor filter.");
671b7073
RB
1247 }
1248 }
1249
9b8e5fb4 1250 protected function mentorJoins()
671b7073
RB
1251 {
1252 $joins = array();
1253 foreach ($this->pms as $sub => $tab) {
5c412626 1254 $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID');
671b7073 1255 }
459e6f81
PC
1256 if ($this->mjtr) {
1257 $joins['mjtr'] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pmt.jtid');
1258 }
671b7073
RB
1259 return $joins;
1260 }
1261
3f42a6ad
FB
1262 /** CONTACTS
1263 */
1264 private $cts = array();
1265 public function addContactFilter($uid = null)
1266 {
c96da6c1 1267 $this->requireProfiles();
3f42a6ad
FB
1268 return $this->register_optional($this->cts, is_null($uid) ? null : 'user_' . $uid);
1269 }
1270
9b8e5fb4 1271 protected function contactJoins()
3f42a6ad
FB
1272 {
1273 $joins = array();
1274 foreach ($this->cts as $sub=>$key) {
1275 if (is_null($key)) {
5c412626 1276 $joins['c' . $sub] = PlSqlJoin::left('contacts', '$ME.contact = $PID');
3f42a6ad 1277 } else {
5c412626 1278 $joins['c' . $sub] = PlSqlJoin::left('contacts', '$ME.uid = {?} AND $ME.contact = $PID', substr($key, 5));
3f42a6ad
FB
1279 }
1280 }
1281 return $joins;
1282 }
4e7bf1e0
FB
1283
1284
1285 /** CARNET
1286 */
1287 private $wn = array();
1288 public function addWatchRegistrationFilter($uid = null)
1289 {
b8dcf62d 1290 $this->requireAccounts();
4e7bf1e0
FB
1291 return $this->register_optional($this->wn, is_null($uid) ? null : 'user_' . $uid);
1292 }
1293
1294 private $wp = array();
1295 public function addWatchPromoFilter($uid = null)
1296 {
b8dcf62d 1297 $this->requireAccounts();
4e7bf1e0
FB
1298 return $this->register_optional($this->wp, is_null($uid) ? null : 'user_' . $uid);
1299 }
1300
1301 private $w = array();
1302 public function addWatchFilter($uid = null)
1303 {
b8dcf62d 1304 $this->requireAccounts();
4e7bf1e0
FB
1305 return $this->register_optional($this->w, is_null($uid) ? null : 'user_' . $uid);
1306 }
1307
9b8e5fb4 1308 protected function watchJoins()
4e7bf1e0
FB
1309 {
1310 $joins = array();
1311 foreach ($this->w as $sub=>$key) {
1312 if (is_null($key)) {
5c412626 1313 $joins['w' . $sub] = PlSqlJoin::left('watch');
4e7bf1e0 1314 } else {
5c412626 1315 $joins['w' . $sub] = PlSqlJoin::left('watch', '$ME.uid = {?}', substr($key, 5));
4e7bf1e0
FB
1316 }
1317 }
1318 foreach ($this->wn as $sub=>$key) {
1319 if (is_null($key)) {
5c412626 1320 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 1321 } else {
5c412626 1322 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5));
4e7bf1e0
FB
1323 }
1324 }
1325 foreach ($this->wn as $sub=>$key) {
1326 if (is_null($key)) {
5c412626 1327 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.ni_id = $UID');
4e7bf1e0 1328 } else {
5c412626 1329 $joins['wn' . $sub] = PlSqlJoin::left('watch_nonins', '$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5));
4e7bf1e0
FB
1330 }
1331 }
1332 foreach ($this->wp as $sub=>$key) {
1333 if (is_null($key)) {
5c412626 1334 $joins['wp' . $sub] = PlSqlJoin::left('watch_promo');
4e7bf1e0 1335 } else {
5c412626 1336 $joins['wp' . $sub] = PlSqlJoin::left('watch_promo', '$ME.uid = {?}', substr($key, 5));
4e7bf1e0
FB
1337 }
1338 }
1339 return $joins;
1340 }
48885bbe
FB
1341
1342
470d14f6
FB
1343 /** PHOTOS
1344 */
1345 private $with_photo;
1346 public function addPhotoFilter()
1347 {
1348 $this->requireProfiles();
1349 $this->with_photo = true;
7f26cd69 1350 return 'photo';
470d14f6
FB
1351 }
1352
1353 protected function photoJoins()
1354 {
1355 if ($this->with_photo) {
1356 return array('photo' => PlSqlJoin::left('profile_photos', '$ME.pid = $PID'));
1357 } else {
1358 return array();
1359 }
1360 }
1361
1362
48885bbe
FB
1363 /** MARKETING
1364 */
1365 private $with_rm;
1366 public function addMarketingHash()
1367 {
1368 $this->requireAccounts();
1369 $this->with_rm = true;
1370 }
1371
1372 protected function marketingJoins()
1373 {
1374 if ($this->with_rm) {
5c412626 1375 return array('rm' => PlSqlJoin::left('register_marketing', '$ME.uid = $UID'));
48885bbe
FB
1376 } else {
1377 return array();
1378 }
1379 }
148af7a9
RB
1380
1381
1382 /** PARTNER SHARING
1383 */
1384
1385 // Lists partner shortnames in use, as a $partner_shortname => true map.
1386 private $ppss = array();
1387
1388 /** Add a filter on user having settings for a given partner.
1389 * @param $partner_id the ID of the partner
1390 * @return the name of the table to use in joins (e.g ppss_$partner_id).
1391 */
1392 public function addPartnerSharingFilter($partner_id)
1393 {
1394 $this->requireProfiles();
f0f8c375 1395 $sub = "ppss_" . $partner_id;
148af7a9
RB
1396 $this->ppss[$sub] = $partner_id;
1397 return $sub;
1398 }
1399
1400 protected function partnerSharingJoins()
1401 {
1402 $joins = array();
1403 foreach ($this->ppss as $sub => $partner_id) {
1404 $joins[$sub] = PlSqlJoin::left('profile_partnersharing_settings', '$ME.pid = $PID AND $ME.partner_id = {?} AND $ME.sharing_level != \'none\'', $partner_id);
1405 }
1406 return $joins;
1407 }
1408
1409 public function restrictVisibilityForPartner($partner_id)
1410 {
1411 $sub = $this->addPartnerSharingFilter($partner_id);
1412 $this->visibility_field = $sub . '.sharing_level';
1413 }
f0f8c375 1414
db492b02
RB
1415 /** VISIBILITY
1416 */
1417 private $vlevels = array();
1418 private $vfields = array();
1419 public function addVisibilityAbsoluteFilter($level)
1420 {
1421 $sub = 'pvel_' . $level;
1422 $this->vlevels[$level] = $sub;
1423 return $sub;
1424 }
1425
1426 public function addVisibilityFieldFilter($field)
1427 {
1428 $sub = 'pvef_' . self::getDBSuffix($field);
1429 $this->vfields[$field] = $sub;
1430 return $sub;
1431 }
1432
f0f8c375
RB
1433 /** Since this method might perform inner joins on tables which have been
1434 * joined previously (e.g when using addVisibilityFieldFilter), it has to
1435 * come after the Joins() methods for those tables.
1436 * This is due to the implementation logic for discovering joins and the
1437 * ordering used by PHP introspection.
1438 */
db492b02
RB
1439 protected function visibilityJoins()
1440 {
1441 $joins = array();
1442 foreach ($this->vlevels as $level => $sub) {
1443 $joins[$sub] = PlSqlJoin::inner('profile_visibility_enum', '$ME.access_level = {?}', $level);
1444 }
1445 foreach ($this->vfields as $field => $sub) {
1446 $joins[$sub] = PlSqlJoin::inner('profile_visibility_enum', '$ME.access_level = ' . $field);
1447 }
1448 return $joins;
1449 }
1450
a087cc8d 1451}
8363588b 1452// }}}
a7d9ab89
RB
1453// {{{ class ProfileFilter
1454class ProfileFilter extends UserFilter
1455{
434570c4 1456 public function get($limit = null)
a7d9ab89
RB
1457 {
1458 return $this->getProfiles($limit);
1459 }
2daf7250 1460
d5fd47bf
SJ
1461 public function getIds($limit = null)
1462 {
1463 return $this->getPIDs();
1464 }
1465
2daf7250
RB
1466 public function filter(array $profiles, $limit = null)
1467 {
1468 return $this->filterProfiles($profiles, self::defaultLimit($limit));
1469 }
1470
1471 public function getTotalCount()
1472 {
1473 return $this->getTotalProfileCount();
1474 }
ccc951d9
RB
1475
1476 public function getGroups()
1477 {
1478 return $this->getPIDGroups();
1479 }
a7d9ab89
RB
1480}
1481// }}}
1482
448c8cdc 1483// vim:set et sw=4 sts=4 sws=4 foldmethod=marker fenc=utf-8:
a087cc8d 1484?>