X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fuserfilter.php;h=f78635b29f1bff36ffb45f695386dddc4181c93a;hb=c76545c351fae4e2298624ff9ee5bf854dc5a5b6;hp=ff446a37c8e1f83b7458e4cf8fa1fefa8cf9868c;hpb=bde68f0508673b04d1a800a2c5078275d14066a6;p=platal.git diff --git a/classes/userfilter.php b/classes/userfilter.php index ff446a3..f78635b 100644 --- a/classes/userfilter.php +++ b/classes/userfilter.php @@ -46,11 +46,31 @@ class UFC_HasProfile implements UserFilterCondition { public function buildCondition(PlFilter &$uf) { + $uf->requireProfiles(); return '$PID IS NOT NULL'; } } // }}} +// {{{ class UFC_AccountType +/** Filters users who have the given account types + */ +class UFC_AccountType implements UserFilterCondition +{ + private $types; + + public function __construct() + { + $this->types = pl_flatten(func_get_args()); + } + + public function buildCondition(PlFilter &$uf) + { + $uf->requireAccounts(); + return XDB::format('a.type IN {?}', $this->types); + } +} + // {{{ class UFC_Hruid /** Filters users based on their hruid * @param $val Either an hruid, or a list of those @@ -59,17 +79,14 @@ class UFC_Hruid implements UserFilterCondition { private $hruids; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->hruids = $val; + $this->hruids = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { - $ufc->requireAccounts(); + $uf->requireAccounts(); return XDB::format('a.hruid IN {?}', $this->hruids); } } @@ -83,12 +100,9 @@ class UFC_Hrpid implements UserFilterCondition { private $hrpids; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->hrpids = $val; + $this->hrpids = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) @@ -134,7 +148,7 @@ class UFC_Comment implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $uf->requireProfiles(); - return 'p.freetext ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->text); + return $uf->getVisibilityCondition('p.freetext_pub') . ' AND p.freetext ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->text); } } // }}} @@ -160,6 +174,10 @@ class UFC_Promo implements UserFilterCondition if ($this->grade != UserFilter::DISPLAY) { UserFilter::assertGrade($this->grade); } + if ($this->grade == UserFilter::DISPLAY && $this->comparison != '=') { + // XXX: we might try to guess the grade from the first char of the promo and forbid only '<= 2004', but allow '<= X2004' + Platal::page()->killError("Il n'est pas possible d'appliquer la comparaison '" . $this->comparison . "' aux promotions sans spécifier de formation (X/M/D)"); + } } public function buildCondition(PlFilter &$uf) @@ -181,7 +199,7 @@ class UFC_Promo implements UserFilterCondition * @param type Parameter type (Xorg, AX, School) * @param value School id value */ -class UFC_SchooldId implements UserFilterCondition +class UFC_SchoolId implements UserFilterCondition { const AX = 'ax'; const Xorg = 'xorg'; @@ -226,12 +244,9 @@ class UFC_EducationSchool implements UserFilterCondition { private $val; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->val = $val; + $this->val = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) @@ -247,18 +262,15 @@ class UFC_EducationDegree implements UserFilterCondition { private $diploma; - public function __construct($diploma) + public function __construct() { - if (! is_array($diploma)) { - $diploma = array($diploma); - } - $this->diploma = $diploma; + $this->diploma = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { $sub = $uf->addEducationFilter(); - return XDB::format('pee' . $sub . '.degreeid IN {?}', $this->val); + return XDB::format('pe' . $sub . '.degreeid IN {?}', $this->diploma); } } // }}} @@ -268,18 +280,15 @@ class UFC_EducationField implements UserFilterCondition { private $val; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->val = $val; + $this->val = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { $sub = $uf->addEducationFilter(); - return XDB::format('pee' . $sub . '.fieldid IN {?}', $this->val); + return XDB::format('pe' . $sub . '.fieldid IN {?}', $this->val); } } // }}} @@ -292,10 +301,11 @@ class UFC_EducationField implements UserFilterCondition */ class UFC_Name implements UserFilterCondition { - const PREFIX = XDB::WILDCARD_PREFIX; // 0x001 - const SUFFIX = XDB::WILDCARD_SUFFIX; // 0x002 + const EXACT = XDB::WILDCARD_EXACT; // 0x000 + const PREFIX = XDB::WILDCARD_PREFIX; // 0x001 + const SUFFIX = XDB::WILDCARD_SUFFIX; // 0x002 const CONTAINS = XDB::WILDCARD_CONTAINS; // 0x003 - const PARTICLE = 0x007; // self::CONTAINS | 0x004 + const PARTICLE = 0x004; const VARIANTS = 0x008; private $type; @@ -353,7 +363,11 @@ class UFC_NameTokens implements UserFilterCondition public function __construct($tokens, $flags = array(), $soundex = false, $exact = false) { - $this->tokens = $tokens; + if (is_array($tokens)) { + $this->tokens = $tokens; + } else { + $this->tokens = array($tokens); + } if (is_array($flags)) { $this->flags = $flags; } else { @@ -365,22 +379,20 @@ class UFC_NameTokens implements UserFilterCondition public function buildCondition(PlFilter &$uf) { - $sub = $uf->addNameTokensFilter(!($this->exact || $this->soundex)); $conds = array(); - if ($this->soundex) { - $conds[] = XDB::format($sub . '.soundex IN {?}', $this->tokens); - } else if ($this->exact) { - $conds[] = XDB::format($sub . '.token IN {?}', $this->tokens); - } else { - $tokconds = array(); - foreach ($this->tokens as $token) { - $tokconds[] = $sub . '.token ' . XDB::formatWildcards(XDB::WILDCARD_PREFIX, $token); + foreach ($this->tokens as $i => $token) { + $sub = $uf->addNameTokensFilter($token); + if ($this->soundex) { + $c = XDB::format($sub . '.soundex = {?}', $token); + } else if ($this->exact) { + $c = XDB::format($sub . '.token = {?}', $token); + } else { + $c = $sub . '.token ' . XDB::formatWildcards(XDB::WILDCARD_PREFIX, $token); } - $conds[] = implode(' OR ', $tokconds); - } - - if ($this->flags != null) { - $conds[] = XDB::format($sub . '.flags IN {?}', $this->flags); + if ($this->flags != null) { + $c .= XDB::format(' AND ' . $sub . '.flags IN {?}', $this->flags); + } + $conds[] = $c; } return implode(' AND ', $conds); @@ -393,12 +405,9 @@ class UFC_Nationality implements UserFilterCondition { private $val; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->val = $val; + $this->val = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) @@ -418,7 +427,7 @@ class UFC_Nationality implements UserFilterCondition // {{{ class UFC_Dead /** Filters users based on death date * @param $comparison Comparison operator - * @param $date Date to which death date should be compared + * @param $date Date to which death date should be compared (DateTime object, string or timestamp) */ class UFC_Dead implements UserFilterCondition { @@ -428,7 +437,7 @@ class UFC_Dead implements UserFilterCondition public function __construct($comparison = null, $date = null) { $this->comparison = $comparison; - $this->date = $date; + $this->date = make_datetime($date); } public function buildCondition(PlFilter &$uf) @@ -436,7 +445,7 @@ class UFC_Dead implements UserFilterCondition $uf->requireProfiles(); $str = 'p.deathdate IS NOT NULL'; if (!is_null($this->comparison)) { - $str .= ' AND p.deathdate ' . $this->comparison . ' ' . XDB::format('{?}', date('Y-m-d', $this->date)); + $str .= ' AND p.deathdate ' . $this->comparison . ' ' . XDB::format('{?}', $this->date->format('Y-m-d')); } return $str; } @@ -459,19 +468,19 @@ class UFC_Registered implements UserFilterCondition { $this->active = $active; $this->comparison = $comparison; - $this->date = $date; + $this->date = make_datetime($date); } public function buildCondition(PlFilter &$uf) { $uf->requireAccounts(); if ($this->active) { - $date = 'a.uid IS NOT NULL AND a.state = \'active\''; + $date = '$UID IS NOT NULL AND a.state = \'active\''; } else { - $date = 'a.uid IS NOT NULL AND a.state != \'pending\''; + $date = '$UID IS NOT NULL AND a.state != \'pending\''; } if (!is_null($this->comparison)) { - $date .= ' AND a.registration_date ' . $this->comparison . ' ' . XDB::format('{?}', date('Y-m-d', $this->date)); + $date .= ' AND a.registration_date != \'0000-00-00 00:00:00\' AND a.registration_date ' . $this->comparison . ' ' . XDB::format('{?}', $this->date->format('Y-m-d')); } return $date; } @@ -567,6 +576,10 @@ class UFC_Group implements UserFilterCondition public function buildCondition(PlFilter &$uf) { + // Groups have AX visibility. + if ($uf->getVisibilityLevel() == ProfileVisibility::VIS_PUBLIC) { + return PlFilter::COND_TRUE; + } $sub = $uf->addGroupFilter($this->group); $where = 'gpm' . $sub . '.perms IS NOT NULL'; if ($this->anim) { @@ -585,16 +598,17 @@ class UFC_Binet implements UserFilterCondition { private $val; - public function __construct($val) + public function __construct() { - if (!is_array($val)) { - $val = array($val); - } - $this->val = $val; + $this->val = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { + // Binets are private. + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } $sub = $uf->addBinetsFilter(); return XDB::format($sub . '.binet_id IN {?}', $this->val); } @@ -609,15 +623,19 @@ class UFC_Section implements UserFilterCondition { private $section; - public function __construct($section) + public function __construct() { - $this->section = $section; + $this->section = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { + // Sections are private. + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } $uf->requireProfiles(); - return 'p.section = ' . XDB::format('{?}', $this->section); + return XDB::format('p.section IN {?}', $this->section); } } // }}} @@ -631,7 +649,7 @@ class UFC_Email implements UserFilterCondition private $emails; public function __construct() { - $this->emails = func_get_args(); + $this->emails = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) @@ -720,9 +738,10 @@ abstract class UFC_Address implements UserFilterCondition $this->flags = $flags; } - protected function initConds($sub) + protected function initConds($sub, $vis_cond) { - $conds = array(); + $conds = array($vis_cond); + $types = array(); foreach (self::$typetexts as $flag => $type) { if ($flag & $this->type) { @@ -730,7 +749,7 @@ abstract class UFC_Address implements UserFilterCondition } } if (count($types)) { - $conds[] = XDB::foramt($sub . '.type IN {?}', $types); + $conds[] = XDB::format($sub . '.type IN {?}', $types); } if ($this->flags != self::FLAG_ANY) { @@ -779,7 +798,7 @@ class UFC_AddressText extends UFC_Address public function buildCondition(PlFilter &$uf) { $sub = $uf->addAddressFilter(); - $conds = $this->initConds($sub); + $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub')); if ($this->text != null) { $conds[] = $sub . '.text' . $this->mkMatch($this->text); } @@ -836,7 +855,7 @@ class UFC_AddressField extends UFC_Address public function buildCondition(PlFilter &$uf) { $sub = $uf->addAddressFilter(); - $conds = $this->initConds($sub); + $conds = $this->initConds($sub, $uf->getVisibilityCondition($sub . '.pub')); switch ($this->fieldtype) { case self::FIELD_COUNTRY: @@ -892,6 +911,7 @@ class UFC_Corps implements UserFilterCondition */ $sub = $uf->addCorpsFilter($this->type); $cond = $sub . '.abbreviation = ' . $corps; + $cond .= ' AND ' . $uf->getVisibilityCondition($sub . '.corps_pub'); return $cond; } } @@ -912,10 +932,14 @@ class UFC_Corps_Rank implements UserFilterCondition public function buildCondition(PlFilter &$uf) { /** Tables shortcuts: + * pc for profile_corps * pcr for profile_corps_rank */ $sub = $uf->addCorpsRankFilter(); $cond = $sub . '.abbreviation = ' . $rank; + // XXX(x2006barrois): find a way to get rid of that hardcoded + // reference to 'pc'. + $cond .= ' AND ' . $uf->getVisibilityCondition('pc.corps_pub'); return $cond; } } @@ -952,7 +976,9 @@ class UFC_Job_Company implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $sub = $uf->addJobCompanyFilter(); - $cond = $sub . '.' . $this->type . ' = ' . XDB::format('{?}', $this->value); + $cond = $sub . '.' . $this->type . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value); + $jsub = $uf->addJobFilter(); + $cond .= ' AND ' . $uf->getVisibilityCondition($jsub . '.pub'); return $cond; } } @@ -988,7 +1014,41 @@ class UFC_Job_Sectorization implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $sub = $uf->addJobSectorizationFilter($this->type); - return $sub . '.id = ' . XDB::format('{?}', $this->val); + $cond = $sub . '.id = ' . XDB::format('{?}', $this->val); + $jsub = $uf->addJobFilter(); + $cond .= ' AND ' . $uf->getVisibilityCondition($jsub . '.pub'); + return $cond; + } +} +// }}} + +// {{{ class UFC_Job_Terms +/** Filters users based on the job terms they assigned to one of their + * jobs. + * @param $val The ID of the job term, or an array of such IDs + */ +class UFC_Job_Terms implements UserFilterCondition +{ + private $val; + + public function __construct($val) + { + if (!is_array($val)) { + $val = array($val); + } + $this->val = $val; + } + + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addJobTermsFilter(count($this->val)); + $conditions = array(); + foreach ($this->val as $i => $jtid) { + $conditions[] = $sub[$i] . '.jtid_1 = ' . XDB::escape($jtid); + } + $jsub = $uf->addJobFilter(); + $conditions[] = $uf->getVisibilityCondition($jsub . '.pub'); + return implode(' AND ', $conditions); } } // }}} @@ -1013,11 +1073,22 @@ class UFC_Job_Description implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $conds = array(); + + $jsub = $uf->addJobFilter(); + // CV is private => if only CV requested, and not private, + // don't do anything. Otherwise restrict to standard job visibility. + if ($this->fields == UserFilter::JOB_CV) { + if ($uf->getVisibilityLevel() != ProfileVisibility::VIS_PRIVATE) { + return PlFilter::COND_TRUE; + } + } else { + $conds[] = $uf->getVisibilityCondition($jsub . '.pub'); + } + if ($this->fields & UserFilter::JOB_USERDEFINED) { - $sub = $uf->addJobFilter(); - $conds[] = $sub . '.description ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); + $conds[] = $jsub . '.description ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); } - if ($this->fields & UserFilter::JOB_CV) { + if ($this->fields & UserFilter::JOB_CV && $uf->getVisibilityLevel == ProfileVisibility::VIS_PRIVATE) { $uf->requireProfiles(); $conds[] = 'p.cv ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->description); } @@ -1060,9 +1131,10 @@ class UFC_Networking implements UserFilterCondition { $sub = $uf->addNetworkingFilter(); $conds = array(); + $conds[] = $uf->getVisibilityCondition($sub . '.pub'); $conds[] = $sub . '.address ' . XDB::formatWildcards(XDB::WILDCARD_CONTAINS, $this->value); if ($this->type != -1) { - $conds[] = $sub . '.network_type = ' . XDB::format('{?}', $this->type); + $conds[] = $sub . '.nwid = ' . XDB::format('{?}', $this->type); } return implode(' AND ', $conds); } @@ -1093,16 +1165,20 @@ class UFC_Phone implements UserFilterCondition public function __construct($number, $num_type = self::NUM_ANY, $phone_type = self::PHONE_ANY) { - require_once('profil.func.inc.php'); - $this->number = $number; + $phone = new Phone(array('display' => $number)); + $phone->format(); + $this->number = $phone->search(); $this->num_type = $num_type; - $this->phone_type = format_phone_number($phone_type); + $this->phone_type = $phone_type; } public function buildCondition(PlFilter &$uf) { $sub = $uf->addPhoneFilter(); $conds = array(); + + $conds[] = $uf->getVisibilityCondition($sub . '.pub'); + $conds[] = $sub . '.search_tel = ' . XDB::format('{?}', $this->number); if ($this->num_type != self::NUM_ANY) { $conds[] = $sub . '.link_type = ' . XDB::format('{?}', $this->num_type); @@ -1134,7 +1210,12 @@ class UFC_Medal implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $conds = array(); + + // This will require profiles => table 'p' will be available. $sub = $uf->addMedalFilter(); + + $conds[] = $uf->getVisibilityCondition('p.medals_pub'); + $conds[] = $sub . '.mid = ' . XDB::format('{?}', $this->medal); if ($this->grade != null) { $conds[] = $sub . '.gid = ' . XDB::format('{?}', $this->grade); @@ -1144,6 +1225,31 @@ class UFC_Medal implements UserFilterCondition } // }}} +// {{{ class UFC_Photo +/** Filters profiles with photo + */ +class UFC_Photo implements UserFilterCondition +{ + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addPhotoFilter(); + return $sub . '.attach IS NOT NULL AND ' . $uf->getVisibilityCondition($sub . '.pub'); + } +} +// }}} + +// {{{ class UFC_Mentor +class UFC_Mentor implements UserFilterCondition +{ + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addMentorFilter(UserFilter::MENTOR); + return $sub . '.expertise IS NOT NULL'; + } +} +// }}} + + // {{{ class UFC_Mentor_Expertise /** Filters users by mentoring expertise * @param $expertise Domain of expertise @@ -1173,15 +1279,36 @@ class UFC_Mentor_Country implements UserFilterCondition { private $country; - public function __construct($country) + public function __construct() { - $this->country = $country; + $this->country = pl_flatten(func_get_args()); } public function buildCondition(PlFilter &$uf) { $sub = $uf->addMentorFilter(UserFilter::MENTOR_COUNTRY); - return $sub . '.country = ' . XDB::format('{?}', $this->country); + return $sub . '.country IN ' . XDB::format('{?}', $this->country); + } +} +// }}} + +// {{{ class UFC_Mentor_Terms +/** Filters users based on the job terms they used in mentoring. + * @param $val The ID of the job term, or an array of such IDs + */ +class UFC_Mentor_Terms implements UserFilterCondition +{ + private $val; + + public function __construct($val) + { + $this->val = $val; + } + + public function buildCondition(PlFilter &$uf) + { + $sub = $uf->addMentorFilter(UserFilter::MENTOR_TERM); + return $sub . '.jtid_1 = ' . XDB::escape($this->val); } } // }}} @@ -1332,28 +1459,12 @@ class UFC_MarketingHash implements UserFilterCondition * ORDERS ******************/ -// {{{ class UserFilterOrder -/** Base class for ordering results of a query. - * Parameters for the ordering must be given to the constructor ($desc for a - * descending order). - * The getSortTokens function is used to get actual ordering part of the query. - */ -abstract class UserFilterOrder extends PlFilterOrder -{ - /** This function must return the tokens to use for ordering - * @param &$uf The UserFilter whose results must be ordered - * @return The name of the field to use for ordering results - */ -// abstract protected function getSortTokens(UserFilter &$uf); -} -// }}} - // {{{ class UFO_Promo /** Orders users by promotion * @param $grade Formation whose promotion users should be sorted by (restricts results to users of that formation) * @param $desc Whether sort is descending */ -class UFO_Promo extends UserFilterOrder +class UFO_Promo extends PlFilterGroupableOrder { private $grade; @@ -1383,7 +1494,7 @@ class UFO_Promo extends UserFilterOrder * @param $particle Set to true if particles should be included in the sorting order * @param $desc If sort order should be descending */ -class UFO_Name extends UserFilterOrder +class UFO_Name extends PlFilterOrder { private $type; private $variant; @@ -1401,7 +1512,13 @@ class UFO_Name extends UserFilterOrder { if (Profile::isDisplayName($this->type)) { $sub = $uf->addDisplayFilter(); - return 'pd' . $sub . '.' . $this->type; + $token = 'pd' . $sub . '.' . $this->type; + if ($uf->accountsRequired()) { + $account_token = Profile::getAccountEquivalentName($this->type); + return 'IFNULL(' . $token . ', a.' . $account_token . ')'; + } else { + return $token; + } } else { $sub = $uf->addNameFilter($this->type, $this->variant); if ($this->particle) { @@ -1415,12 +1532,22 @@ class UFO_Name extends UserFilterOrder // }}} // {{{ class UFO_Score -class UFO_Score extends UserFilterOrder +class UFO_Score extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { - $sub = $uf->addNameTokensFilter(); - return 'SUM(' . $sub . '.score)'; + $toks = $uf->getNameTokens(); + $scores = array(); + + // If there weren't any sort tokens, we shouldn't sort by score, sort by NULL instead + if (count($toks) == 0) { + return 'NULL'; + } + + foreach ($toks as $sub => $token) { + $scores[] = XDB::format('SUM(' . $sub . '.score + IF (' . $sub . '.token = {?}, 5, 0) )', $token); + } + return implode(' + ', $scores); } } // }}} @@ -1428,10 +1555,11 @@ class UFO_Score extends UserFilterOrder // {{{ class UFO_Registration /** Sorts users based on registration date */ -class UFO_Registration extends UserFilterOrder +class UFO_Registration extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { + $uf->requireAccounts(); return 'a.registration_date'; } } @@ -1440,10 +1568,11 @@ class UFO_Registration extends UserFilterOrder // {{{ class UFO_Birthday /** Sorts users based on next birthday date */ -class UFO_Birthday extends UserFilterOrder +class UFO_Birthday extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { + $uf->requireProfiles(); return 'p.next_birthday'; } } @@ -1452,10 +1581,11 @@ class UFO_Birthday extends UserFilterOrder // {{{ class UFO_ProfileUpdate /** Sorts users based on last profile update */ -class UFO_ProfileUpdate extends UserFilterOrder +class UFO_ProfileUpdate extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { + $uf->requireProfiles(); return 'p.last_change'; } } @@ -1464,15 +1594,68 @@ class UFO_ProfileUpdate extends UserFilterOrder // {{{ class UFO_Death /** Sorts users based on death date */ -class UFO_Death extends UserFilterOrder +class UFO_Death extends PlFilterOrder { protected function getSortTokens(PlFilter &$uf) { + $uf->requireProfiles(); return 'p.deathdate'; } } // }}} +// {{{ class UFO_Uid +/** Sorts users based on their uid + */ +class UFO_Uid extends PlFilterOrder +{ + protected function getSortTokens(PlFilter &$uf) + { + $uf->requireAccounts(); + return '$UID'; + } +} +// }}} + +// {{{ class UFO_Hruid +/** Sorts users based on their hruid + */ +class UFO_Hruid extends PlFilterOrder +{ + protected function getSortTokens(PlFilter &$uf) + { + $uf->requireAccounts(); + return 'a.hruid'; + } +} +// }}} + +// {{{ class UFO_Pid +/** Sorts users based on their pid + */ +class UFO_Pid extends PlFilterOrder +{ + protected function getSortTokens(PlFilter &$uf) + { + $uf->requireProfiles(); + return '$PID'; + } +} +// }}} + +// {{{ class UFO_Hrpid +/** Sorts users based on their hrpid + */ +class UFO_Hrpid extends PlFilterOrder +{ + protected function getSortTokens(PlFilter &$uf) + { + $uf->requireProfiles(); + return 'p.hrpid'; + } +} +// }}} + /*********************************** ********************************* @@ -1512,7 +1695,7 @@ class UFO_Death extends UserFilterOrder * when referring to the joined table. * * For example, if data from profile_job must be available to filter results, - * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and + * the UFC object will call $uf-addJobFilter(), which will set the 'with_pj' var and * return 'pj', the short name to use when referring to profile_job; when building * the query, calling the jobJoins function will return an array containing a single * row: @@ -1532,10 +1715,15 @@ class UserFilter extends PlFilter private $root; private $sort = array(); + private $grouper = null; private $query = null; private $orderby = null; - private $lastcount = null; + // Store the current 'search' visibility. + private $profile_visibility = null; + + private $lastusercount = null; + private $lastprofilecount = null; public function __construct($cond = null, $sort = null) { @@ -1554,7 +1742,7 @@ class UserFilter extends PlFilter } } if (!is_null($sort)) { - if ($sort instanceof UserFilterOrder) { + if ($sort instanceof PlFilterOrder) { $this->addSort($sort); } else if (is_array($sort)) { foreach ($sort as $s) { @@ -1562,10 +1750,41 @@ class UserFilter extends PlFilter } } } + + // This will set the visibility to the default correct level. + $this->profile_visibility = new ProfileVisibility(); + } + + public function getVisibilityLevels() + { + return $this->profile_visibility->levels(); + } + + public function getVisibilityLevel() + { + return $this->profile_visibility->level(); + } + + public function restrictVisibilityTo($level) + { + $this->profile_visibility->setLevel($level); + } + + public function getVisibilityCondition($field) + { + return $field . ' IN ' . XDB::formatArray($this->getVisibilityLevels()); } private function buildQuery() { + // The root condition is built first because some orders need info + // available only once all UFC have set their conditions (UFO_Score) + if (is_null($this->query)) { + $where = $this->root->buildCondition($this); + $where = str_replace(array_keys($this->joinMetas), + $this->joinMetas, + $where); + } if (is_null($this->orderby)) { $orders = array(); foreach ($this->sort as $sort) { @@ -1576,13 +1795,12 @@ class UserFilter extends PlFilter } else { $this->orderby = 'ORDER BY ' . implode(', ', $orders); } + $this->orderby = str_replace(array_keys($this->joinMetas), + $this->joinMetas, + $this->orderby); } if (is_null($this->query)) { - $where = $this->root->buildCondition($this); - if ($this->with_forced_sn) { - $this->requireProfiles(); - $from = 'search_name AS sn'; - } else if ($this->with_accounts) { + if ($this->with_accounts) { $from = 'accounts AS a'; } else { $this->requireProfiles(); @@ -1595,13 +1813,49 @@ class UserFilter extends PlFilter } } + public function hasGroups() + { + return $this->grouper != null; + } + + public function getGroups() + { + return $this->getUIDGroups(); + } + + public function getUIDGroups() + { + $this->requireAccounts(); + $this->buildQuery(); + $token = $this->grouper->getGroupToken($this); + + $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(a.uid) + ' . $this->query . ' + GROUP BY ' . $token, + 0); + return $groups; + } + + public function getPIDGroups() + { + $this->requireProfiles(); + $this->buildQuery(); + $token = $this->grouper->getGroupToken($this); + + $groups = XDB::fetchAllRow('SELECT ' . $token . ', COUNT(p.pid) + ' . $this->query . ' + GROUP BY ' . $token, + 0); + return $groups; + } + private function getUIDList($uids = null, PlLimit &$limit) { $this->requireAccounts(); $this->buildQuery(); $lim = $limit->getSql(); $cond = ''; - if (!is_null($uids)) { + if (!empty($uids)) { $cond = XDB::format(' AND a.uid IN {?}', $uids); } $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid @@ -1609,7 +1863,7 @@ class UserFilter extends PlFilter GROUP BY a.uid ' . $this->orderby . ' ' . $lim); - $this->lastcount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()'); + $this->lastusercount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()'); return $fetched; } @@ -1627,7 +1881,7 @@ class UserFilter extends PlFilter GROUP BY p.pid ' . $this->orderby . ' ' . $lim); - $this->lastcount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()'); + $this->lastprofilecount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()'); return $fetched; } @@ -1728,7 +1982,7 @@ class UserFilter extends PlFilter public function getUID($pos = 0) { - $uids =$this->getUIDList(null, new PlFilter(1, $pos)); + $uids =$this->getUIDList(null, new PlLimit(1, $pos)); if (count($uids) == 0) { return null; } else { @@ -1744,7 +1998,7 @@ class UserFilter extends PlFilter public function getPID($pos = 0) { - $pids =$this->getPIDList(null, new PlFilter(1, $pos)); + $pids =$this->getPIDList(null, new PlLimit(1, $pos)); if (count($pids) == 0) { return null; } else { @@ -1772,24 +2026,24 @@ class UserFilter extends PlFilter return User::iterOverUIDs($this->getUIDs($limit)); } - public function getProfiles($limit = null) + public function getProfiles($limit = null, $fields = 0x0000, $visibility = null) { - return Profile::getBulkProfilesWithPIDs($this->getPIDs($limit)); + return Profile::getBulkProfilesWithPIDs($this->getPIDs($limit), $fields, $visibility); } - public function getProfile($pos = 0) + public function getProfile($pos = 0, $fields = 0x0000, $visibility = null) { $pid = $this->getPID($pos); if ($pid == null) { return null; } else { - return Profile::get($pid); + return Profile::get($pid, $fields, $visibility); } } - public function iterProfiles($limit = null) + public function iterProfiles($limit = null, $fields = 0x0000, $visibility = null) { - return Profile::iterOverPIDs($this->getPIDs($limit)); + return Profile::iterOverPIDs($this->getPIDs($limit), true, $fields, $visibility); } public function get($limit = null) @@ -1797,19 +2051,33 @@ class UserFilter extends PlFilter return $this->getUsers($limit); } + public function getTotalCount() { - if (is_null($this->lastcount)) { + return $this->getTotalUserCount(); + } + + public function getTotalUserCount() + { + if (is_null($this->lastusercount)) { + $this->requireAccounts(); $this->buildQuery(); - if ($this->with_accounts) { - $field = 'a.uid'; - } else { - $field = 'p.pid'; - } - return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT ' . $field . ') + return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT a.uid) ' . $this->query); } else { - return $this->lastcount; + return $this->lastusercount; + } + } + + public function getTotalProfileCount() + { + if (is_null($this->lastprofilecount)) { + $this->requireProfiles(); + $this->buildQuery(); + return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT p.pid) + ' . $this->query); + } else { + return $this->lastprofilecount; } } @@ -1821,6 +2089,10 @@ class UserFilter extends PlFilter public function addSort(PlFilterOrder &$sort) { + if (count($this->sort) == 0 && $sort instanceof PlFilterGroupableOrder) + { + $this->grouper = $sort; + } $this->sort[] = $sort; $this->orderby = null; } @@ -1887,34 +2159,30 @@ class UserFilter extends PlFilter */ private $with_profiles = false; private $with_accounts = false; - private $with_forced_sn = false; public function requireAccounts() { $this->with_accounts = true; } + public function accountsRequired() + { + return $this->with_accounts; + } + public function requireProfiles() { $this->with_profiles = true; } - /** Forces the "FROM" to use search_name instead of accounts or profiles */ - public function forceSearchName() + public function profilesRequired() { - $this->with_forced_sn = true; + return $this->with_profiles; } protected function accountJoins() { $joins = array(); - /** Quick search is much more efficient with sn first and PID second */ - if ($this->with_forced_sn) { - $joins['p'] = PlSqlJoin::left('profiles', '$PID = sn.pid'); - if ($this->with_accounts) { - $joins['ap'] = PlSqlJoin::left('account_profiles', '$ME.pid = $PID'); - $joins['a'] = PlSqlJoin::left('accounts', '$UID = ap.uid'); - } - } else if ($this->with_profiles && $this->with_accounts) { + if ($this->with_profiles && $this->with_accounts) { $joins['ap'] = PlSqlJoin::left('account_profiles', '$ME.uid = $UID AND FIND_IN_SET(\'owner\', ap.perms)'); $joins['p'] = PlSqlJoin::left('profiles', '$PID = ap.pid'); } @@ -1965,7 +2233,7 @@ class UserFilter extends PlFilter static public function assertName($name) { - if (!Profile::getNameTypeId($name)) { + if (!DirEnum::getID(DirEnum::NAMETYPES, $name)) { Platal::page()->kill('Invalid name type: ' . $name); } } @@ -1985,7 +2253,7 @@ class UserFilter extends PlFilter if (!is_null($variant) && $variant == 'other') { $sub .= $this->option++; } - $this->pn[$sub] = Profile::getNameTypeId($ft); + $this->pn[$sub] = DirEnum::getID(DirEnum::NAMETYPES, $ft); return $sub; } @@ -2000,26 +2268,31 @@ class UserFilter extends PlFilter /** NAMETOKENS */ - private $with_sn = false; - // Set $doingQuickSearch to true if you wish to optimize the query - public function addNameTokensFilter($doingQuickSearch = false) + private $name_tokens = array(); + private $nb_tokens = 0; + + public function addNameTokensFilter($token) { $this->requireProfiles(); - $this->with_forced_sn = ($this->with_forced_sn || $doingQuickSearch); - $this->with_sn = true; - return 'sn'; + $sub = 'sn' . (1 + $this->nb_tokens); + $this->nb_tokens++; + $this->name_tokens[$sub] = $token; + return $sub; } protected function nameTokensJoins() { /* We don't return joins, since with_sn forces the SELECT to run on search_name first */ - if ($this->with_sn && !$this->with_forced_sn) { - return array( - 'sn' => PlSqlJoin::left('search_name', '$ME.pid = $PID') - ); - } else { - return array(); + $joins = array(); + foreach ($this->name_tokens as $sub => $token) { + $joins[$sub] = PlSqlJoin::left('search_name', '$ME.pid = $PID'); } + return $joins; + } + + public function getNameTokens() + { + return $this->name_tokens; } /** NATIONALITY @@ -2048,7 +2321,7 @@ class UserFilter extends PlFilter const GRADE_MST = 'M%'; static public function isGrade($grade) { - return $grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST; + return ($grade !== 0) && ($grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST); } static public function assertGrade($grade) @@ -2110,7 +2383,7 @@ class UserFilter extends PlFilter { $this->requireAccounts(); if (!is_null($group)) { - if (ctype_digit($group)) { + if (is_int($group) || ctype_digit($group)) { $index = $sub = $group; } else { $index = $group; @@ -2132,7 +2405,7 @@ class UserFilter extends PlFilter if (is_null($key)) { $joins['gpa' . $sub] = PlSqlJoin::inner('groups'); $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = gpa' . $sub . '.id'); - } else if (ctype_digit($key)) { + } else if (is_int($key) || ctype_digit($key)) { $joins['gpm' . $sub] = PlSqlJoin::left('group_members', '$ME.uid = $UID AND $ME.asso_id = ' . $key); } else { $joins['gpa' . $sub] = PlSqlJoin::inner('groups', '$ME.diminutif = {?}', $key); @@ -2207,8 +2480,8 @@ class UserFilter extends PlFilter if (!is_array($key)) { $key = array($key); } - $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\' - AND $ME.email IN {?}' . $key); + $joins['e' . $sub] = PlSqlJoin::left('emails', '$ME.uid = $UID AND $ME.flags != \'filter\' + AND $ME.email IN {?}', $key); } } foreach ($this->al as $sub=>$key) { @@ -2222,7 +2495,7 @@ class UserFilter extends PlFilter if (!is_array($key)) { $key = array($key); } - $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') + $joins['al' . $sub] = PlSqlJoin::left('aliases', '$ME.uid = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND $ME.alias IN {?}', $key); } } @@ -2352,6 +2625,7 @@ class UserFilter extends PlFilter * pjsse => profile_job_subsector_enum * pjssse => profile_job_subsubsector_enum * pja => profile_job_alternates + * pjt => profile_job_terms */ private $with_pj = false; private $with_pje = false; @@ -2359,6 +2633,7 @@ class UserFilter extends PlFilter private $with_pjsse = false; private $with_pjssse = false; private $with_pja = false; + private $with_pjt = 0; public function addJobFilter() { @@ -2392,6 +2667,21 @@ class UserFilter extends PlFilter } } + /** + * Adds a filter on job terms of profile. + * @param $nb the number of job terms to use + * @return an array of the fields to filter (one for each term). + */ + public function addJobTermsFilter($nb = 1) + { + $this->with_pjt = $nb; + $jobtermstable = array(); + for ($i = 1; $i <= $nb; ++$i) { + $jobtermstable[] = 'pjtr_'.$i; + } + return $jobtermstable; + } + protected function jobJoins() { $joins = array(); @@ -2413,6 +2703,12 @@ class UserFilter extends PlFilter if ($this->with_pja) { $joins['pja'] = PlSqlJoin::left('profile_job_alternates', '$ME.subsubsectorid = pj.subsubsectorid'); } + if ($this->with_pjt > 0) { + for ($i = 1; $i <= $this->with_pjt; ++$i) { + $joins['pjt_'.$i] = PlSqlJoin::left('profile_job_term', '$ME.pid = $PID'); + $joins['pjtr_'.$i] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pjt_'.$i.'.jtid'); + } + } return $joins; } @@ -2481,14 +2777,20 @@ class UserFilter extends PlFilter */ private $pms = array(); - const MENTOR_EXPERTISE = 1; - const MENTOR_COUNTRY = 2; - const MENTOR_SECTOR = 3; + private $mjtr = false; + const MENTOR = 1; + const MENTOR_EXPERTISE = 2; + const MENTOR_COUNTRY = 3; + const MENTOR_SECTOR = 4; + const MENTOR_TERM = 5; public function addMentorFilter($type) { $this->requireAccounts(); switch($type) { + case self::MENTOR: + $this->pms['pm'] = 'profile_mentor'; + return 'pm'; case self::MENTOR_EXPERTISE: $this->pms['pme'] = 'profile_mentor'; return 'pme'; @@ -2498,6 +2800,10 @@ class UserFilter extends PlFilter case self::MENTOR_SECTOR: $this->pms['pms'] = 'profile_mentor_sector'; return 'pms'; + case self::MENTOR_TERM: + $this->pms['pmt'] = 'profile_mentor_term'; + $this->mjtr = true; + return 'mjtr'; default: Platal::page()->killError("Undefined mentor filter."); } @@ -2509,6 +2815,9 @@ class UserFilter extends PlFilter foreach ($this->pms as $sub => $tab) { $joins[$sub] = PlSqlJoin::left($tab, '$ME.pid = $PID'); } + if ($this->mjtr) { + $joins['mjtr'] = PlSqlJoin::left('profile_job_term_relation', '$ME.jtid_2 = pmt.jtid'); + } return $joins; } @@ -2593,6 +2902,26 @@ class UserFilter extends PlFilter } + /** PHOTOS + */ + private $with_photo; + public function addPhotoFilter() + { + $this->requireProfiles(); + $this->with_photo = true; + return 'photo'; + } + + protected function photoJoins() + { + if ($this->with_photo) { + return array('photo' => PlSqlJoin::left('profile_photos', '$ME.pid = $PID')); + } else { + return array(); + } + } + + /** MARKETING */ private $with_rm; @@ -2620,6 +2949,21 @@ class ProfileFilter extends UserFilter { return $this->getProfiles($limit); } + + public function filter(array $profiles, $limit = null) + { + return $this->filterProfiles($profiles, self::defaultLimit($limit)); + } + + public function getTotalCount() + { + return $this->getTotalProfileCount(); + } + + public function getGroups() + { + return $this->getPIDGroups(); + } } // }}}