+// }}}
+
+// {{{ class UFC_Email
+/** Filters users based on email address
+ * @param $email Email whose owner we are looking for
+ */
+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
+/** Filters users based on an email list
+ * @param $emails List of emails whose owner must be selected
+ */
+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) . ')';
+ }
+}
+// }}}
+
+// {{{ class UFC_Address
+/** Filters users based on their address
+ * @param $text Text for filter in fulltext search
+ * @param $textSearchMode Mode for search (PREFIX, SUFFIX, ...)
+ * @param $type Filter on address type
+ * @param $flags Filter on address flags
+ * @param $countryId Filter on address countryId
+ * @param $administrativeAreaId Filter on address administrativeAreaId
+ * @param $subAdministrativeAreaId Filter on address subAdministrativeAreaId
+ * @param $localityId Filter on address localityId
+ * @param $postalCode Filter on address postalCode
+ */
+class UFC_Address implements UserFilterCondition
+{
+ /** Flags for text search
+ */
+ const PREFIX = 0x0001;
+ const SUFFIX = 0x0002;
+ const CONTAINS = 0x0003;
+
+ /** Valid address type ('hq' is reserved for company addresses)
+ */
+ const TYPE_HOME = 'home';
+ const TYPE_PRO = 'job';
+
+ /** Flags for addresses
+ */
+ const FLAG_CURRENT = 0x0001;
+ const FLAG_TEMP = 0x0002;
+ const FLAG_SECOND = 0x0004;
+ const FLAG_MAIL = 0x0008;
+ const FLAG_CEDEX = 0x0010;
+
+ // Binary OR of those flags
+ const FLAG_ANY = 0x001F;
+
+ /** Text of these flags
+ */
+ private static $flagtexts = array(
+ self::FLAG_CURRENT => 'current',
+ self::FLAG_TEMP => 'temporary',
+ self::FLAG_SECOND => 'secondary',
+ self::FLAG_MAIL => 'mail',
+ self::FLAG_CEDEX => 'cedex',
+ );
+
+ /** Data of the filter
+ */
+ private $text;
+ private $type;
+ private $flags;
+ private $countryId;
+ private $administrativeAreaId;
+ private $subAdministrativeAreaId;
+ private $localityId;
+ private $postalCode;
+
+ private $textSearchMode;
+
+ public function __construct($text = null, $textSearchMode = self::CONTAINS,
+ $type = null, $flags = self::FLAG_ANY, $countryId = null, $administrativeAreaId = null,
+ $subAdministrativeAreaId = null, $localityId = null, $postalCode = null)
+ {
+ $this->text = $text;
+ $this->textSearchMode = $textSearchMode;
+ $this->type = $type;
+ $this->flags = $flags;
+ $this->countryId = $countryId;
+ $this->administrativeAreaId = $administrativeAreaId;
+ $this->subAdministrativeAreaId = $subAdministrativeAreaId;
+ $this->localityId = $localityId;
+ $this->postalCode = $postalCode;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addAddressFilter();
+ $conds = array();
+ if ($this->text != null) {
+ $left = $sub . '.text ';
+ $op = ' LIKE ';
+ if (($this->textSearchMode & self::CONTAINS) == 0) {
+ $right = XDB::format('{?}', $this->text);
+ $op = ' = ';
+ } else if (($this->mode & self::CONTAINS) == self::PREFIX) {
+ $right = XDB::format('CONCAT({?}, \'%\')', $this->text);
+ } else if (($this->mode & self::CONTAINS) == self::SUFFIX) {
+ $right = XDB::format('CONCAT(\'%\', {?})', $this->text);
+ } else {
+ $right = XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->text);
+ }
+ $conds[] = $left . $op . $right;
+ }
+
+ if ($this->type != null) {
+ $conds[] = $sub . '.type = ' . XDB::format('{?}', $this->type);
+ }
+
+ if ($this->flags != self::FLAG_ANY) {
+ foreach(self::$flagtexts as $flag => $text) {
+ if ($flag & $this->flags) {
+ $conds[] = 'FIND_IN_SET(' . XDB::format('{?}', $text) . ', ' . $sub . '.flags)';
+ }
+ }
+ }
+
+ if ($this->countryId != null) {
+ $conds[] = $sub . '.countryId = ' . XDB::format('{?}', $this->countryId);
+ }
+ if ($this->administrativeAreaId != null) {
+ $conds[] = $sub . '.administrativeAreaId = ' . XDB::format('{?}', $this->administrativeAreaId);
+ }
+ if ($this->subAdministrativeAreaId != null) {
+ $conds[] = $sub . '.subAdministrativeAreaId = ' . XDB::format('{?}', $this->subAdministrativeAreaId);
+ }
+ if ($this->localityId != null) {
+ $conds[] = $sub . '.localityId = ' . XDB::format('{?}', $this->localityId);
+ }
+ if ($this->postalCode != null) {
+ $conds[] = $sub . '.postalCode = ' . XDB::format('{?}', $this->postalCode);
+ }
+
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Corps
+/** Filters users based on the corps they belong to
+ * @param $corps Corps we are looking for (abbreviation)
+ * @param $type Whether we search for original or current corps
+ */
+class UFC_Corps implements UserFilterCondition
+{
+ const CURRENT = 1;
+ const ORIGIN = 2;
+
+ private $corps;
+ private $type;
+
+ public function __construct($corps, $type = self::CURRENT)
+ {
+ $this->corps = $corps;
+ $this->type = $type;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ /** Tables shortcuts:
+ * pc for profile_corps,
+ * pceo for profile_corps_enum - orginal
+ * pcec for profile_corps_enum - current
+ */
+ $sub = $uf->addCorpsFilter($this->type);
+ $cond = $sub . '.abbreviation = ' . $corps;
+ return $cond;
+ }
+}
+// }}}
+
+// {{{ class UFC_Corps_Rank
+/** Filters users based on their rank in the corps
+ * @param $rank Rank we are looking for (abbreviation)
+ */
+class UFC_Corps_Rank implements UserFilterCondition
+{
+ private $rank;
+ public function __construct($rank)
+ {
+ $this->rank = $rank;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ /** Tables shortcuts:
+ * pcr for profile_corps_rank
+ */
+ $sub = $uf->addCorpsRankFilter();
+ $cond = $sub . '.abbreviation = ' . $rank;
+ return $cond;
+ }
+}
+// }}}
+
+// {{{ class UFC_Job_Company
+/** Filters users based on the company they belong to
+ * @param $type The field being searched (self::JOBID, self::JOBNAME or self::JOBACRONYM)
+ * @param $value The searched value
+ */
+class UFC_Job_Company implements UserFilterCondition
+{
+ const JOBID = 'id';
+ const JOBNAME = 'name';
+ const JOBACRONYM = 'acronym';
+
+ private $type;
+ private $value;
+
+ public function __construct($type, $value)
+ {
+ $this->assertType($type);
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ private function assertType($type)
+ {
+ if ($type != self::JOBID && $type != self::JOBNAME && $type != self::JOBACRONYM) {
+ Platal::page()->killError("Type de recherche non valide.");
+ }
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addJobCompanyFilter();
+ $cond = $sub . '.' . $this->type . ' = ' . XDB::format('{?}', $this->value);
+ return $cond;
+ }
+}
+// }}}
+
+// {{{ class UFC_Job_Sectorization
+/** Filters users based on the ((sub)sub)sector they work in
+ * @param $sector The sector searched
+ * @param $subsector The subsector
+ * @param $subsubsector The subsubsector
+ */
+class UFC_Job_Sectorization implements UserFilterCondition
+{
+
+ private $sector;
+ private $subsector;
+ private $subsubsector;
+
+ public function __construct($sector = null, $subsector = null, $subsubsector = null)
+ {
+ $this->sector = $sector;
+ $this->subsector = $subsector;
+ $this->subsubsector = $subsubsector;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ // No need to add the JobFilter, it will be done by addJobSectorizationFilter
+ $conds = array();
+ if ($this->sector !== null) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SECTOR);
+ $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->sector);
+ }
+ if ($this->subsector !== null) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSECTOR);
+ $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->subsector);
+ }
+ if ($this->subsubsector !== null) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSUBSECTOR);
+ $conds[] = $sub . '.id = ' . XDB::format('{?}', $this->subsubsector);
+ }
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Job_Description
+/** Filters users based on their job description
+ * @param $description The text being searched for
+ * @param $fields The fields to search for (user-defined, ((sub|)sub|)sector)
+ */
+class UFC_Job_Description implements UserFilterCondition
+{
+
+ /** Meta-filters
+ * Built with binary OR on UserFilter::JOB_*
+ */
+ const ANY = 31;
+ const SECTORIZATION = 15;
+
+ private $description;
+ private $fields;
+
+ public function __construct($description)
+ {
+ $this->fields = $fields;
+ $this->description = $description;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $conds = array();
+ if ($this->fields & UserFilter::JOB_USERDEFINED) {
+ $sub = $uf->addJobFilter();
+ $conds[] = $sub . '.description LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
+ }
+ if ($this->fields & UserFilter::JOB_SECTOR) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SECTOR);
+ $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
+ }
+ if ($this->fields & UserFilter::JOB_SUBSECTOR) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSECTOR);
+ $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
+ }
+ if ($this->fields & UserFilter::JOB_SUBSUBSECTOR) {
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_SUBSUBSECTOR);
+ $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
+ $sub = $uf->addJobSectorizationFilter(UserFilter::JOB_ALTERNATES);
+ $conds[] = $sub . '.name LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->description);
+ }
+ return implode(' OR ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Networking
+/** Filters users based on network identity (IRC, ...)
+ * @param $type Type of network (-1 for any)
+ * @param $value Value to search
+ */
+class UFC_Networking implements UserFilterCondition
+{
+ private $type;
+ private $value;
+
+ public function __construct($type, $value)
+ {
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addNetworkingFilter();
+ $conds = array();
+ $conds[] = $sub . '.address = ' . XDB::format('CONCAT(\'%\', {?}, \'%\')', $this->value);
+ if ($this->type != -1) {
+ $conds[] = $sub . '.network_type = ' . XDB::format('{?}', $this->type);
+ }
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Phone
+/** Filters users based on their phone number
+ * @param $num_type Type of number (pro/user/home)
+ * @param $phone_type Type of phone (fixed/mobile/fax)
+ * @param $number Phone number
+ */
+class UFC_Phone implements UserFilterCondition
+{
+ const NUM_PRO = 'pro';
+ const NUM_USER = 'user';
+ const NUM_HOME = 'address';
+ const NUM_ANY = 'any';
+
+ const PHONE_FIXED = 'fixed';
+ const PHONE_MOBILE = 'mobile';
+ const PHONE_FAX = 'fax';
+ const PHONE_ANY = 'any';
+
+ private $num_type;
+ private $phone_type;
+ private $number;
+
+ public function __construct($number, $num_type = self::NUM_ANY, $phone_type = self::PHONE_ANY)
+ {
+ require_once('profil.inc.php');
+ $this->number = $number;
+ $this->num_type = $num_type;
+ $this->phone_type = format_phone_number($phone_type);
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addPhoneFilter();
+ $conds = array();
+ $conds[] = $sub . '.search_tel = ' . XDB::format('{?}', $this->number);
+ if ($this->num_type != self::NUM_ANY) {
+ $conds[] = $sub . '.link_type = ' . XDB::format('{?}', $this->num_type);
+ }
+ if ($this->phone_type != self::PHONE_ANY) {
+ $conds[] = $sub . '.tel_type = ' . XDB::format('{?}', $this->phone_type);
+ }
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Medal
+/** Filters users based on their medals
+ * @param $medal ID of the medal
+ * @param $grade Grade of the medal (null for 'any')
+ */
+class UFC_Medal implements UserFilterCondition
+{
+ private $medal;
+ private $grade;
+
+ public function __construct($medal, $grade = null)
+ {
+ $this->medal = $medal;
+ $this->grade = $grade;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $conds = array();
+ $sub = $uf->addMedalFilter();
+ $conds[] = $sub . '.mid = ' . XDB::format('{?}', $this->medal);
+ if ($this->grade != null) {
+ $conds[] = $sub . '.gid = ' . XDB::format('{?}', $this->grade);
+ }
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_Mentor_Expertise
+/** Filters users by mentoring expertise
+ * @param $expertise Domain of expertise
+ */
+class UFC_Mentor_Expertise implements UserFilterCondition
+{
+ private $expertise;
+
+ public function __construct($expertise)
+ {
+ $this->expertise = $expertise;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addMentorFilter(UserFilter::MENTOR_EXPERTISE);
+ return $sub . '.expertise LIKE ' . XDB::format('CONCAT(\'%\', {?}, \'%\'', $this->expertise);
+ }
+}
+// }}}
+
+// {{{ class UFC_Mentor_Country
+/** Filters users by mentoring country
+ * @param $country Two-letters code of country being searched
+ */
+class UFC_Mentor_Country implements UserFilterCondition
+{
+ private $country;
+
+ public function __construct($country)
+ {
+ $this->country = $country;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addMentorFilter(UserFilter::MENTOR_COUNTRY);
+ return $sub . '.country = ' . XDB::format('{?}', $this->country);
+ }
+}
+// }}}
+
+// {{{ class UFC_Mentor_Sectorization
+/** Filters users based on mentoring (sub|)sector
+ * @param $sector ID of sector
+ * @param $subsector Subsector (null for any)
+ */
+class UFC_Mentor_Sectorization implements UserFilterCondition
+{
+ private $sector;
+ private $subsector;
+
+ public function __construct($sector, $subsector = null)
+ {
+ $this->sector = $sector;
+ $this->subsubsector = $subsector;
+ }
+
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addMentorFilter(UserFilter::MENTOR_SECTOR);
+ $conds = array();
+ $conds[] = $sub . '.sectorid = ' . XDB::format('{?}', $this->sector);
+ if ($this->subsector != null) {
+ $conds[] = $sub . '.subsectorid = ' . XDB::format('{?}', $this->subsector);
+ }
+ return implode(' AND ', $conds);
+ }
+}
+// }}}
+
+// {{{ class UFC_UserRelated
+/** Filters users based on a relation toward a user
+ * @param $user User to which searched users are related
+ */
+abstract class UFC_UserRelated implements UserFilterCondition
+{
+ protected $user;
+ public function __construct(PlUser &$user)
+ {
+ $this->user =& $user;
+ }
+}
+// }}}
+
+// {{{ class UFC_Contact
+/** Filters users who belong to selected user's contacts
+ */
+class UFC_Contact extends UFC_UserRelated
+{
+ public function buildCondition(UserFilter &$uf)
+ {
+ $sub = $uf->addContactFilter($this->user->id());
+ return 'c' . $sub . '.contact IS NOT NULL';
+ }
+}
+// }}}