X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;ds=inline;f=classes%2Fuserfilter.php;h=30a7029cac9f3cd4300b13cad621605b548f9554;hb=c52d86d1d876e6def108e1d458604cc9714c252d;hp=7a4dd3bf853f915758bccbda67055fb9691707fc;hpb=24e08e33cff3f567f8603dc576d103819e2349a2;p=platal.git diff --git a/classes/userfilter.php b/classes/userfilter.php index 7a4dd3b..30a7029 100644 --- a/classes/userfilter.php +++ b/classes/userfilter.php @@ -19,6 +19,11 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ***************************************************************************/ + +/****************** + * CONDITIONS + ******************/ + interface UserFilterCondition { const COND_TRUE = 'TRUE'; @@ -168,20 +173,21 @@ class UFC_Promo implements UserFilterCondition $this->grade = $grade; $this->comparison = $comparison; $this->promo = $promo; - UserFilter::assertGrade($this->grade); + if ($this->grade != UserFilter::DISPLAY) { + UserFilter::assertGrade($this->grade); + } } public function buildCondition(UserFilter &$uf) { - // XXX: Definition of promotion for phds and masters might change in near future. - if ($this->grade == UserFilter::GRADE_ING) { - $promo_year = 'entry_year'; + if ($this->grade == UserFilter::DISPLAY) { + $sub = $uf->addDisplayFilter(); + return XDB::format('pd' . $sub . '.promo = {?}', $this->promo); } else { - $promo_year = 'grad_year'; + $sub = $uf->addEducationFilter(true, $this->grade); + $field = 'pe' . $sub . '.' . UserFilter::promoYear($this->grade); + return $field . ' IS NOT NULL AND ' . $field . ' ' . $this->comparison . ' ' . XDB::format('{?}', $this->promo); } - $sub = $uf->addEducationFilter(true, $this->grade); - $field = 'pe' . $sub . '.' . $promo_year; - return $field . ' IS NOT NULL AND ' . $field . ' ' . $this->comparison . ' ' . XDB::format('{?}', $this->promo); } } @@ -229,7 +235,7 @@ class UFC_Name implements UserFilterCondition } $cond = $left . $op . $right; $conds = array($this->buildNameQuery($this->type, null, $cond, $uf)); - if (($this->mode & self::VARIANTS) != 0) { + if (($this->mode & self::VARIANTS) != 0 && isset(UserFilter::$name_variants[$this->type])) { foreach (UserFilter::$name_variants[$this->type] as $var) { $conds[] = $this->buildNameQuery($this->type, $var, $cond, $uf); } @@ -240,37 +246,83 @@ class UFC_Name implements UserFilterCondition class UFC_Dead implements UserFilterCondition { - private $dead; - public function __construct($dead) + private $comparison; + private $date; + + public function __construct($comparison = null, $date = null) { - $this->dead = $dead; + $this->comparison = $comparison; + $this->date = $date; } public function buildCondition(UserFilter &$uf) { - if ($this->dead) { - return 'p.deathdate IS NOT NULL'; - } else { - return 'p.deathdate IS NULL'; + $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)); } + return $str; } } class UFC_Registered implements UserFilterCondition { private $active; - public function __construct($active = false) + private $comparison; + private $date; + + public function __construct($active = false, $comparison = null, $date = null) { $this->only_active = $active; + $this->comparison = $comparison; + $this->date = $date; } public function buildCondition(UserFilter &$uf) { if ($this->active) { - return 'a.uid IS NOT NULL AND a.state = \'active\''; + $date = 'a.uid IS NOT NULL AND a.state = \'active\''; } else { - return 'a.uid IS NOT NULL AND a.state != \'pending\''; + $date = 'a.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)); } + return $date; + } +} + +class UFC_ProfileUpdated implements UserFilterCondition +{ + private $comparison; + private $date; + + public function __construct($comparison = null, $date = null) + { + $this->comparison = $comparison; + $this->date = $date; + } + + public function buildCondition(UserFilter &$uf) + { + return 'p.last_change ' . $this->comparison . XDB::format(' {?}', date('Y-m-d H:i:s', $this->date)); + } +} + +class UFC_Birthday implements UserFilterCondition +{ + private $comparison; + private $date; + + public function __construct($comparison = null, $date = null) + { + $this->comparison = $comparison; + $this->date = $date; + } + + public function buildCondition(UserFilter &$uf) + { + return 'p.next_birthday ' . $this->comparison . XDB::format(' {?}', date('Y-m-d', $this->date)); } } @@ -313,15 +365,282 @@ class UFC_Group implements UserFilterCondition } } +class UFC_Email implements UserFilterCondition +{ + private $email; + public function __construct($email) + { + $this->email = $email; + } + + public function buildCondition(UserFilter &$uf) + { + if (User::isForeignEmailAddress($this->email)) { + $sub = $uf->addEmailRedirectFilter($this->email); + return XDB::format('e' . $sub . '.email IS NOT NULL OR a.email = {?}', $this->email); + } else if (User::isVirtualEmailAddress($this->email)) { + $sub = $uf->addVirtualEmailFilter($this->email); + return 'vr' . $sub . '.redirect IS NOT NULL'; + } else { + @list($user, $domain) = explode('@', $this->email); + $sub = $uf->addAliasFilter($user); + return 'al' . $sub . '.alias IS NOT NULL'; + } + } +} + +class UFC_EmailList implements UserFilterCondition +{ + private $emails; + public function __construct($emails) + { + $this->emails = $emails; + } + + public function buildCondition(UserFilter &$uf) + { + $email = null; + $virtual = null; + $alias = null; + $cond = array(); + + if (count($this->emails) == 0) { + return UserFilterCondition::COND_TRUE; + } + + foreach ($this->emails as $entry) { + if (User::isForeignEmailAddress($entry)) { + if (is_null($email)) { + $email = $uf->addEmailRedirectFilter(); + } + $cond[] = XDB::format('e' . $email . '.email = {?} OR a.email = {?}', $entry, $entry); + } else if (User::isVirtualEmailAddress($entry)) { + if (is_null($virtual)) { + $virtual = $uf->addVirtualEmailFilter(); + } + $cond[] = XDB::format('vr' . $virtual . '.redirect IS NOT NULL AND v' . $virtual . '.alias = {?}', $entry); + } else { + if (is_null($alias)) { + $alias = $uf->addAliasFilter(); + } + @list($user, $domain) = explode('@', $entry); + $cond[] = XDB::format('al' . $alias . '.alias = {?}', $user); + } + } + return '(' . implode(') OR (', $cond) . ')'; + } +} + +abstract class UFC_UserRelated implements UserFilterCondition +{ + protected $user; + public function __construct(PlUser &$user) + { + $this->user =& $user; + } +} + +class UFC_Contact extends UFC_UserRelated +{ + public function buildCondition(UserFilter &$uf) + { + $sub = $uf->addContactFilter($this->user->id()); + return 'c' . $sub . '.contact IS NOT NULL'; + } +} + +class UFC_WatchRegistration extends UFC_UserRelated +{ + public function buildCondition(UserFilter &$uf) + { + if (!$this->user->watch('registration')) { + return UserFilterCondition::COND_FALSE; + } + $uids = $this->user->watchUsers(); + if (count($uids) == 0) { + return UserFilterCondition::COND_FALSE; + } else { + return '$UID IN ' . XDB::formatArray($uids); + } + } +} + +class UFC_WatchPromo extends UFC_UserRelated +{ + private $grade; + public function __construct(PlUser &$user, $grade = UserFilter::GRADE_ING) + { + parent::__construct($user); + $this->grade = $grade; + } + + public function buildCondition(UserFilter &$uf) + { + $promos = $this->user->watchPromos(); + if (count($promos) == 0) { + return UserFilterCondition::COND_FALSE; + } else { + $sube = $uf->addEducationFilter(true, $this->grade); + $field = 'pe' . $sube . '.' . UserFilter::promoYear($this->grade); + return $field . ' IN ' . XDB::formatArray($promos); + } + } +} + +class UFC_WatchContact extends UFC_Contact +{ + public function buildCondition(UserFilter &$uf) + { + if (!$this->user->watchContacts()) { + return UserFilterCondition::COND_FALSE; + } + return parent::buildCondition($uf); + } +} + + +/****************** + * ORDERS + ******************/ + +abstract class UserFilterOrder +{ + protected $desc = false; + public function __construct($desc = false) + { + $this->desc = $desc; + } + + public function buildSort(UserFilter &$uf) + { + $sel = $this->getSortTokens($uf); + if (!is_array($sel)) { + $sel = array($sel); + } + if ($this->desc) { + foreach ($sel as $k=>$s) { + $sel[$k] = $s . ' DESC'; + } + } + return $sel; + } + + abstract protected function getSortTokens(UserFilter &$uf); +} + +class UFO_Promo extends UserFilterOrder +{ + private $grade; + + public function __construct($grade = null, $desc = false) + { + parent::__construct($desc); + $this->grade = $grade; + } + + protected function getSortTokens(UserFilter &$uf) + { + if (UserFilter::isGrade($this->grade)) { + $sub = $uf->addEducationFilter($this->grade); + return 'pe' . $sub . '.' . UserFilter::promoYear($this->grade); + } else { + $sub = $uf->addDisplayFilter(); + return 'pd' . $sub . '.promo'; + } + } +} + +class UFO_Name extends UserFilterOrder +{ + private $type; + private $variant; + private $particle; + + public function __construct($type, $variant = null, $particle = false, $desc = false) + { + parent::__construct($desc); + $this->type = $type; + $this->variant = $variant; + $this->particle = $particle; + } + + protected function getSortTokens(UserFilter &$uf) + { + if (UserFilter::isDisplayName($this->type)) { + $sub = $uf->addDisplayFilter(); + return 'pd' . $sub . '.' . $this->type; + } else { + $sub = $uf->addNameFilter($this->type, $this->variant); + if ($this->particle) { + return 'CONCAT(pn' . $sub . '.particle, \' \', pn' . $sub . '.name)'; + } else { + return 'pn' . $sub . '.name'; + } + } + } +} + +class UFO_Registration extends UserFilterOrder +{ + protected function getSortTokens(UserFilter &$uf) + { + return 'a.registration_date'; + } +} + +class UFO_Birthday extends UserFilterOrder +{ + protected function getSortTokens(UserFilter &$uf) + { + return 'p.next_birthday'; + } +} + +class UFO_ProfileUpdate extends UserFilterOrder +{ + protected function getSortTokens(UserFilter &$uf) + { + return 'p.last_change'; + } +} + +class UFO_Death extends UserFilterOrder +{ + protected function getSortTokens(UserFilter &$uf) + { + return 'p.deathdate'; + } +} + + +/*********************************** + ********************************* + USER FILTER CLASS + ********************************* + ***********************************/ + class UserFilter { + static private $joinMethods = array(); + private $root; private $sort = array(); private $query = null; private $orderby = null; + private $lastcount = null; + public function __construct($cond = null, $sort = null) { + if (empty(self::$joinMethods)) { + $class = new ReflectionClass('UserFilter'); + foreach ($class->getMethods() as $method) { + $name = $method->getName(); + if (substr($name, -5) == 'Joins' && $name != 'buildJoins') { + self::$joinMethods[] = $name; + } + } + } if (!is_null($cond)) { if ($cond instanceof UserFilterCondition) { $this->setCondition($cond); @@ -330,12 +649,27 @@ class UserFilter if (!is_null($sort)) { if ($sort instanceof UserFilterOrder) { $this->addSort($sort); + } else if (is_array($sort)) { + foreach ($sort as $s) { + $this->addSort($s); + } } } } private function buildQuery() { + if (is_null($this->orderby)) { + $orders = array(); + foreach ($this->sort as $sort) { + $orders = array_merge($orders, $sort->buildSort($this)); + } + if (count($orders) == 0) { + $this->orderby = ''; + } else { + $this->orderby = 'ORDER BY ' . implode(', ', $orders); + } + } if (is_null($this->query)) { $where = $this->root->buildCondition($this); $joins = $this->buildJoins(); @@ -345,9 +679,6 @@ class UserFilter ' . $joins . ' WHERE (' . $where . ')'; } - if (is_null($this->sortby)) { - $this->sortby = ''; - } } private function formatJoin(array $joins) @@ -374,10 +705,37 @@ class UserFilter private function buildJoins() { - $joins = $this->educationJoins() + $this->nameJoins() + $this->groupJoins(); + $joins = array(); + foreach (self::$joinMethods as $method) { + $joins = array_merge($joins, $this->$method()); + } return $this->formatJoin($joins); } + private function getUIDList($uids = null, $count = null, $offset = null) + { + $this->buildQuery(); + $limit = ''; + if (!is_null($count)) { + if (!is_null($offset)) { + $limit = XDB::format('LIMIT {?}, {?}', $offset, $count); + } else { + $limit = XDB::format('LIMIT {?}', $count); + } + } + $cond = ''; + if (!is_null($uids)) { + $cond = ' AND a.uid IN ' . XDB::formatArray($uids); + } + $fetched = XDB::fetchColumn('SELECT SQL_CALC_FOUND_ROWS a.uid + ' . $this->query . $cond . ' + GROUP BY a.uid + ' . $this->orderby . ' + ' . $limit); + $this->lastcount = (int)XDB::fetchOneCell('SELECT FOUND_ROWS()'); + return $fetched; + } + /** Check that the user match the given rule. */ public function checkUser(PlUser &$user) @@ -390,18 +748,21 @@ class UserFilter /** Filter a list of user to extract the users matching the rule. */ - public function filter(array $users) + public function filter(array $users, $count = null, $offset = null) { $this->buildQuery(); $table = array(); $uids = array(); foreach ($users as $user) { - $uids[] = $user->id(); - $table[$user->id()] = $user; + if ($user instanceof PlUser) { + $uid = $user->id(); + } else { + $uid = $user; + } + $uids[] = $uid; + $table[$uid] = $user; } - $fetched = XDB::fetchColumn('SELECT a.uid - ' . $this->query . ' AND a.uid IN (' . implode(', ', $uids) . ') - GROUP BY a.uid'); + $fetched = $this->getUIDList($uids, $count, $offset); $output = array(); foreach ($fetched as $uid) { $output[] = $table[$uid]; @@ -409,17 +770,25 @@ class UserFilter return $output; } - public function getUIDs() + public function getUIDs($count = null, $offset = null) { - $this->buildQuery(); - return XDB::fetchColumn('SELECT a.uid - ' . $this->query . ' - GROUP BY a.uid'); + return $this->getUIDList(null, $count, $offset); + } + + public function getUsers($count = null, $offset = null) + { + return User::getBulkUsersWithUIDs($this->getUIDs($count, $offset)); } - public function getUsers() + public function getTotalCount() { - return User::getBuildUsersWithUIDs($this->getUIDs()); + if (is_null($this->lastcount)) { + $this->buildQuery(); + return (int)XDB::fetchOneCell('SELECT COUNT(DISTINCT a.uid) + ' . $this->query); + } else { + return $this->lastcount; + } } public function setCondition(UserFilterCondition &$cond) @@ -430,8 +799,8 @@ class UserFilter public function addSort(UserFilterOrder &$sort) { - $this->sort[] =& $sort; - $this->sortby = null; + $this->sort[] = $sort; + $this->orderby = null; } static public function getLegacy($promo_min, $promo_max) @@ -449,24 +818,83 @@ class UserFilter return new UserFilter(new UFC_And($min, $max)); } + static public function sortByName() + { + return array(new UFO_Name(self::LASTNAME), new UFO_Name(self::FIRSTNAME)); + } + + static public function sortByPromo() + { + return array(new UFO_Promo(), new UFO_Name(self::LASTNAME), new UFO_Name(self::FIRSTNAME)); + } + + static private function getDBSuffix($string) + { + return preg_replace('/[^a-z0-9]/i', '', $string); + } + + + private $option = 0; + private function register_optional(array &$table, $val) + { + if (is_null($val)) { + $sub = $this->option++; + $index = null; + } else { + $sub = self::getDBSuffix($val); + $index = $val; + } + $sub = '_' . $sub; + $table[$sub] = $index; + return $sub; + } + + /** DISPLAY + */ + const DISPLAY = 'display'; + private $pd = false; + public function addDisplayFilter() + { + $this->pd = true; + return ''; + } + + private function displayJoins() + { + if ($this->pd) { + return array('pd' => array('left', 'profile_display', '$ME.pid = $PID')); + } else { + return array(); + } + } /** NAMES */ + /* name tokens */ const LASTNAME = 'lastname'; const FIRSTNAME = 'firstname'; const NICKNAME = 'nickname'; const PSEUDONYM = 'pseudonym'; const NAME = 'name'; + /* name variants */ const VN_MARITAL = 'marital'; const VN_ORDINARY = 'ordinary'; const VN_OTHER = 'other'; const VN_INI = 'ini'; + /* display names */ + const DN_FULL = 'directory_name'; + const DN_DISPLAY = 'yourself'; + const DN_YOURSELF = 'yourself'; + const DN_DIRECTORY = 'directory_name'; + const DN_PRIVATE = 'private_name'; + const DN_PUBLIC = 'public_name'; + const DN_SHORT = 'short_name'; + const DN_SORT = 'sort_name'; static public $name_variants = array( self::LASTNAME => array(self::VN_MARITAL, self::VN_ORDINARY), - self::FIRSTNAME => array(self::VN_ORDINARY, self::VN_INI, self::VN_OTHER), - self::NICKNAME => array(), self::PSEUDONYM => array(), - self::NAME => array()); + self::FIRSTNAME => array(self::VN_ORDINARY, self::VN_INI, self::VN_OTHER) + ); static public function assertName($name) { @@ -475,8 +903,15 @@ class UserFilter } } + static public function isDisplayName($name) + { + return $name == self::DN_FULL || $name == self::DN_DISPLAY + || $name == self::DN_YOURSELF || $name == self::DN_DIRECTORY + || $name == self::DN_PRIVATE || $name == self::DN_PUBLIC + || $name == self::DN_SHORT || $name == self::DN_SORT; + } + private $pn = array(); - private $pno = 0; public function addNameFilter($type, $variant = null) { if (!is_null($variant)) { @@ -488,7 +923,7 @@ class UserFilter self::assertName($ft); if (!is_null($variant) && $variant == 'other') { - $sub .= $this->pno++; + $sub .= $this->option++; } $this->pn[$sub] = Profile::getNameTypeId($ft); return $sub; @@ -511,7 +946,7 @@ class UserFilter const GRADE_MST = 'M%'; static public function isGrade($grade) { - return $grade == self::GRADE_ING || self::$grade == GRADE_PHD || self::$grade == GRADE_MST; + return $grade == self::GRADE_ING || $grade == self::GRADE_PHD || $grade == self::GRADE_MST; } static public function assertGrade($grade) @@ -521,14 +956,19 @@ class UserFilter } } + static public function promoYear($grade) + { + // XXX: Definition of promotion for phds and masters might change in near future. + return ($grade == UserFilter::GRADE_ING) ? 'entry_year' : 'grad_year'; + } + private $pepe = array(); private $with_pee = false; - private $pe_g = 0; public function addEducationFilter($x = false, $grade = null) { if (!$x) { - $index = $this->pe_g; - $sub = $this->pe_g++; + $index = $this->option; + $sub = $this->option++; } else { self::assertGrade($grade); $index = $grade; @@ -564,7 +1004,6 @@ class UserFilter /** GROUPS */ private $gpm = array(); - private $gpm_o = 0; public function addGroupFilter($group = null) { if (!is_null($group)) { @@ -572,10 +1011,10 @@ class UserFilter $index = $sub = $group; } else { $index = $group; - $sub = preg_replace('/[^a-z0-9]/i', '', $group); + $sub = self::getDBSuffix($group); } } else { - $sub = 'group_' . $this->gpm_o++; + $sub = 'group_' . $this->option++; $index = null; } $sub = '_' . $sub; @@ -599,7 +1038,145 @@ class UserFilter } return $joins; } + + /** EMAILS + */ + private $e = array(); + public function addEmailRedirectFilter($email = null) + { + return $this->register_optional($this->e, $email); + } + + private $ve = array(); + public function addVirtualEmailFilter($email = null) + { + $this->addAliasFilter(self::ALIAS_FORLIFE); + return $this->register_optional($this->ve, $email); + } + + const ALIAS_BEST = 'bestalias'; + const ALIAS_FORLIFE = 'forlife'; + private $al = array(); + public function addAliasFilter($alias = null) + { + return $this->register_optional($this->al, $alias); + } + + private function emailJoins() + { + global $globals; + $joins = array(); + foreach ($this->e as $sub=>$key) { + if (is_null($key)) { + $joins['e' . $sub] = array('left', 'emails', '$ME.uid = $UID AND $ME.flags != \'filter\''); + } else { + $joins['e' . $sub] = array('left', 'emails', XDB::format('$ME.uid = $UID AND $ME.flags != \'filter\' AND $ME.email = {?}', $key)); + } + } + foreach ($this->al as $sub=>$key) { + if (is_null($key)) { + $joins['al' . $sub] = array('left', 'aliases', '$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\')'); + } else if ($key == self::ALIAS_BEST) { + $joins['al' . $sub] = array('left', 'aliases', '$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND FIND_IN_SET(\'bestalias\', $ME.flags)'); + } else if ($key == self::ALIAS_FORLIFE) { + $joins['al' . $sub] = array('left', 'aliases', '$ME.id = $UID AND $ME.type = \'a_vie\''); + } else { + $joins['al' . $sub] = array('left', 'aliases', XDB::format('$ME.id = $UID AND $ME.type IN (\'alias\', \'a_vie\') AND $ME.alias = {?}', $key)); + } + } + foreach ($this->ve as $sub=>$key) { + if (is_null($key)) { + $joins['v' . $sub] = array('left', 'virtual', '$ME.type = \'user\''); + } else { + $joins['v' . $sub] = array('left', 'virtual', XDB::format('$ME.type = \'user\' AND $ME.alias = {?}', $key)); + } + $joins['vr' . $sub] = array('left', 'virtual_redirect', XDB::format('$ME.vid = v' . $sub . '.vid + AND ($ME.redirect IN (CONCAT(al_forlife.alias, \'@\', {?}), + CONCAT(al_forlife.alias, \'@\', {?}), + a.email))', + $globals->mail->domain, $globals->mail->domain2)); + } + return $joins; + } + + + /** CONTACTS + */ + private $cts = array(); + public function addContactFilter($uid = null) + { + return $this->register_optional($this->cts, is_null($uid) ? null : 'user_' . $uid); + } + + private function contactJoins() + { + $joins = array(); + foreach ($this->cts as $sub=>$key) { + if (is_null($key)) { + $joins['c' . $sub] = array('left', 'contacts', '$ME.contact = $UID'); + } else { + $joins['c' . $sub] = array('left', 'contacts', XDB::format('$ME.uid = {?} AND $ME.contact = $UID', substr($key, 5))); + } + } + return $joins; + } + + + /** CARNET + */ + private $wn = array(); + public function addWatchRegistrationFilter($uid = null) + { + return $this->register_optional($this->wn, is_null($uid) ? null : 'user_' . $uid); + } + + private $wp = array(); + public function addWatchPromoFilter($uid = null) + { + return $this->register_optional($this->wp, is_null($uid) ? null : 'user_' . $uid); + } + + private $w = array(); + public function addWatchFilter($uid = null) + { + return $this->register_optional($this->w, is_null($uid) ? null : 'user_' . $uid); + } + + private function watchJoins() + { + $joins = array(); + foreach ($this->w as $sub=>$key) { + if (is_null($key)) { + $joins['w' . $sub] = array('left', 'watch'); + } else { + $joins['w' . $sub] = array('left', 'watch', XDB::format('$ME.uid = {?}', substr($key, 5))); + } + } + foreach ($this->wn as $sub=>$key) { + if (is_null($key)) { + $joins['wn' . $sub] = array('left', 'watch_nonins', '$ME.ni_id = $UID'); + } else { + $joins['wn' . $sub] = array('left', 'watch_nonins', XDB::format('$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5))); + } + } + foreach ($this->wn as $sub=>$key) { + if (is_null($key)) { + $joins['wn' . $sub] = array('left', 'watch_nonins', '$ME.ni_id = $UID'); + } else { + $joins['wn' . $sub] = array('left', 'watch_nonins', XDB::format('$ME.uid = {?} AND $ME.ni_id = $UID', substr($key, 5))); + } + } + foreach ($this->wp as $sub=>$key) { + if (is_null($key)) { + $joins['wp' . $sub] = array('left', 'watch_promo'); + } else { + $joins['wp' . $sub] = array('left', 'watch_promo', XDB::format('$ME.uid = {?}', substr($key, 5))); + } + } + return $joins; + } } + // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: ?>