X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fuserfilter.php;h=2a9d077a9f6640d61165c4fe820918c080026d22;hb=ccc951d9ef4b747cf4c5b08d52e6f8938338f6de;hp=f95feb9c2b362d02311dc7292f21b9981ce62034;hpb=8fcb783abab541b33476550a1acd1a7ae5c9b711;p=platal.git diff --git a/classes/userfilter.php b/classes/userfilter.php index f95feb9..2a9d077 100644 --- a/classes/userfilter.php +++ b/classes/userfilter.php @@ -47,7 +47,7 @@ class UFC_HasProfile implements UserFilterCondition public function buildCondition(PlFilter &$uf) { $uf->requireProfiles(); - return 'p.pid IS NOT NULL'; + return '$PID IS NOT NULL'; } } // }}} @@ -155,6 +155,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) @@ -356,22 +360,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); @@ -416,13 +418,7 @@ class UFC_Dead implements UserFilterCondition public function __construct($comparison = null, $date = null) { $this->comparison = $comparison; - if ($date instanceof DateTime) { - $this->date = $date; - } else if (is_int($date)) { - $this->date = new DateTime("@$date"); - } else { - $this->date = new DateTime($date); - } + $this->date = make_datetime($date); } public function buildCondition(PlFilter &$uf) @@ -453,19 +449,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; } @@ -943,7 +939,7 @@ 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); return $cond; } } @@ -1053,7 +1049,7 @@ class UFC_Networking implements UserFilterCondition $conds = array(); $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); } @@ -1084,10 +1080,11 @@ 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) @@ -1336,28 +1333,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; @@ -1387,7 +1368,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; @@ -1405,7 +1386,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) { @@ -1419,12 +1406,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); } } // }}} @@ -1432,10 +1429,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'; } } @@ -1444,10 +1442,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'; } } @@ -1456,10 +1455,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'; } } @@ -1468,15 +1468,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'; + } +} +// }}} + /*********************************** ********************************* @@ -1516,7 +1569,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: @@ -1536,6 +1589,7 @@ class UserFilter extends PlFilter private $root; private $sort = array(); + private $grouper = null; private $query = null; private $orderby = null; @@ -1559,7 +1613,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) { @@ -1571,6 +1625,14 @@ class UserFilter extends PlFilter 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) { @@ -1581,13 +1643,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(); @@ -1600,13 +1661,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 @@ -1733,7 +1830,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 { @@ -1749,7 +1846,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 { @@ -1840,6 +1937,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; } @@ -1906,34 +2007,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'); } @@ -2019,26 +2116,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 @@ -2226,8 +2328,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) { @@ -2241,7 +2343,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); } } @@ -2668,6 +2770,11 @@ class ProfileFilter extends UserFilter { return $this->getTotalProfileCount(); } + + public function getGroups() + { + return $this->getPIDGroups(); + } } // }}}