Support of networking in profile.
[platal.git] / classes / profile.php
CommitLineData
e7b93962
FB
1<?php
2/***************************************************************************
34ade5a6 3 * Copyright (C) 2003-2009 Polytechnique.org *
e7b93962
FB
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22class Profile
23{
f5642983
FB
24 static private $v_values = array('public' => array('public'),
25 'ax' => array('ax', 'public'),
26 'private' => array('private', 'ax', 'public'));
27 const VISIBILITY_PUBLIC = 'public';
28 const VISIBILITY_AX = 'ax';
29 const VISIBILITY_PRIVATE = 'private';
30
31 const ADDRESS_MAIN = 0x000001;
32 const ADDRESS_PERSO = 0x000002;
33 const ADDRESS_PRO = 0x000004;
34 const ADDRESS_ALL = 0x000006;
35 const ADDRESS_POSTAL = 0x000008;
36
37 const EDUCATION_MAIN = 0x000010;
4bc5b8f0
FB
38 const EDUCATION_EXTRA = 0x000020;
39 const EDUCATION_ALL = 0x000040;
40 const EDUCATION_FINISHED = 0x000080;
41 const EDUCATION_CURRENT = 0x000100;
f5642983 42
4bc5b8f0
FB
43 const JOBS_MAIN = 0x001000;
44 const JOBS_ALL = 0x002000;
45 const JOBS_FINISHED = 0x004000;
46 const JOBS_CURRENT = 0x008000;
f5642983 47
04a94b1d
FB
48 const NETWORKING_ALL = 0x000000;
49 const NETWORKING_WEB = 0x010000;
50 const NETWORKING_IM = 0x020000;
51 const NETWORKING_SOCIAL = 0x040000;
52
e7b93962
FB
53 private $pid;
54 private $hrpid;
3e53a496
FB
55 private $data = array();
56
f5642983
FB
57 private $visibility = null;
58
b774ddab 59 private function __construct(array $data)
e7b93962 60 {
b774ddab 61 $this->data = $data;
832e6fcb
FB
62 $this->pid = $this->data['pid'];
63 $this->hrpid = $this->data['hrpid'];
e7b93962
FB
64 }
65
66 public function id()
67 {
68 return $this->pid;
69 }
70
71 public function hrid()
72 {
73 return $this->hrpid;
74 }
75
d5e60905
FB
76 public function promo()
77 {
78 return $this->promo;
79 }
80
94b72319
FB
81 /** Print a name with the given formatting:
82 * %s = • for women
83 * %f = firstname
84 * %l = lastname
85 * %F = fullname
86 * %S = shortname
87 * %p = promo
88 */
89 public function name($format)
90 {
91 return str_replace(array('%s', '%f', '%l', '%F', '%S', '%p'),
92 array($this->isFemale() ? '•' : '',
93 $this->first_name, $this->last_name,
94 $this->full_name, $this->short_name,
95 $this->promo), $format);
96 }
97
98 public function fullName($with_promo = false)
99 {
100 if ($with_promo) {
101 return $this->full_name . ' (' . $this->promo . ')';
102 }
103 return $this->full_name;
104 }
105
106 public function shortName($with_promo = false)
107 {
108 if ($with_promo) {
109 return $this->short_name . ' (' . $this->promo . ')';
110 }
111 return $this->short_name;
112 }
113
114 public function firstName()
115 {
08c91036 116 return $this->firstname;
94b72319
FB
117 }
118
119 public function lastName()
120 {
08c91036 121 return $this->lastname;
94b72319
FB
122 }
123
124 public function isFemale()
125 {
126 return $this->sex == PlUser::GENDER_FEMALE;
127 }
128
129 public function data()
130 {
131 $this->first_name;
132 return $this->data;
133 }
134
3e53a496
FB
135 public function __get($name)
136 {
137 if (property_exists($this, $name)) {
138 return $this->$name;
139 }
140
3e53a496
FB
141 if (isset($this->data[$name])) {
142 return $this->data[$name];
143 }
144
145 return null;
146 }
147
148 public function __isset($name)
149 {
150 return property_exists($this, $name) || isset($this->data[$name]);
151 }
152
f5642983
FB
153 public function setVisibilityLevel($visibility)
154 {
155 if ($visibility != self::VISIBILITY_PRIVATE
156 && $visibility != self::VISIBILITY_AX
157 && $visibility != self::VISIBILITY_PUBLIC) {
158 Platal::page()->kill("Visibility invalide: " . $visibility);
159 }
160 $this->visibility = self::$v_values[$visibility];
46e9eb99
FB
161 if ($this->mobile && !in_array($this->modbile_pub, $this->visibility)) {
162 unset($this->data['mobile']);
163 }
f5642983
FB
164 }
165
4bc5b8f0
FB
166
167 /* Addresses
168 */
169 public function getAddresses($flags, $limit = null)
f5642983
FB
170 {
171 $where = XDB::format('pa.pid = {?}', $this->id());
172 if ($flags & self::ADDRESS_MAIN) {
173 $where .= ' AND FIND_IN_SET(\'current\', pa.flags)';
174 }
175 if ($flags & self::ADDRESS_POSTAL) {
176 $where .= ' AND FIND_IN_SET(\'mail\', pa.flags)';
177 }
178 if ($this->visibility) {
179 $where .= ' AND pa.pub IN ' . XDB::formatArray($this->visibility);
180 }
181 $type = array();
182 if ($flags & self::ADDRESS_PRO) {
183 $type[] = 'job';
184 }
185 if ($flags & self::ADDRESS_PERSO) {
186 $type[] = 'home';
187 }
188 if (count($type) > 0) {
189 $where .= ' AND pa.type IN ' . XDB::formatArray($type);
190 }
4bc5b8f0 191 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
f5642983
FB
192 return XDB::iterator('SELECT pa.text, pa.postalCode, pa.type, pa.latitude, pa.longitude,
193 gl.name AS locality, gas.name AS subAdministrativeArea,
194 ga.name AS administrativeArea, gc.countryFR AS country,
195 FIND_IN_SET(\'current\', pa.flags) AS current,
196 FIND_IN_SET(\'temporary\', pa.flags) AS temporary,
197 FIND_IN_SET(\'secondary\', pa.flags) AS secondary,
198 FIND_IN_SET(\'mail\', pa.flags) AS mail, pa.type
199 FROM profile_addresses AS pa
200 LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId)
201 LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId)
202 LEFT JOIN geoloc_administrativeareas AS gas ON (gas.id = pa.subAdministrativeAreaId)
203 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId)
4bc5b8f0
FB
204 WHERE ' . $where . '
205 ORDER BY pa.id
206 ' . $limit);
f5642983
FB
207 }
208
209 public function getMainAddress()
210 {
211 $it = $this->getAddresses(self::ADDRESS_PERSO | self::ADDRESS_MAIN);
212 if ($it->total() == 0) {
213 return null;
214 } else {
215 return $it->next();
216 }
217 }
3e53a496 218
4bc5b8f0
FB
219
220 /* Educations
221 */
222 public function getEducations($flags, $limit = null)
223 {
224 $where = XDB::format('pe.uid = {?}', $this->id());
225 if ($flags & self::EDUCATION_MAIN) {
226 $where .= ' AND FIND_IN_SET(\'primary\', pe.flags)';
227 } else if ($flags & self::EDUCATION_EXTRA) {
228 $where .= ' AND NOT FIND_IN_SET(\'primary\', pe.flags)';
229 } else if ($flags & self::EDUCATION_FINISHED) {
230 $where .= ' AND pe.grad_year <= YEAR(CURDATE())';
231 } else if ($flags & self::EDUCATION_CURRENT) {
232 $where .= ' AND pe.grad_year > YEAR(CURDATE())';
233 }
234 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
235 return XDB::iterator('SELECT pe.entry_year, pe.grad_year, pe.program,
236 pee.name AS school, pee.abbreviation AS school_short, pee.url AS school_url, gc.countryFR AS country,
237 pede.degree, pede.abbreviation AS degree_short, pede.level AS degree_level, pefe.field,
238 FIND_IN_SET(\'primary\', pe.flags) AS prim
239 FROM profile_education AS pe
240 INNER JOIN profile_education_enum AS pee ON (pe.eduid = pee.id)
241 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pee.country)
242 INNER JOIN profile_education_degree_enum AS pede ON (pe.degreeid = pede.id)
243 LEFT JOIN profile_education_field_enum AS pefe ON (pe.fieldid = pefe.id)
244 WHERE ' . $where . '
245 ORDER BY NOT FIND_IN_SET(\'primary\', pe.flags), pe.entry_year, pe.id
246 ' . $limit);
247 }
248
249 public function getExtraEducations($limit = null)
250 {
251 return $this->getEducations(self::EDUCATION_EXTRA, $limit);
252 }
253
254
04a94b1d
FB
255 /** Networking
256 */
257
258 public function getNetworking($flags, $limit = null)
259 {
260 $where = XDB::format('pn.uid = {?}', $this->id());
261 if ($flags & self::NETWORKING_WEB) {
262 $where .= ' AND pn.network_type = 0'; // XXX hardcoded reference to web site index
263 }
264 if ($this->visibility) {
265 $where .= ' AND pn.pub IN ' . XDB::formatArray($this->visibility);
266 }
267 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
268 return XDB::iterator('SELECT pne.name, pne.icon,
269 IF (LENGTH(pne.link) > 0, REPLACE(pne.link, \'%s\', pn.address),
270 pn.address) AS address
271 FROM profile_networking AS pn
272 INNER JOIN profile_networking_enum AS pne ON (pn.network_type = pne.network_type)
273 WHERE ' . $where . '
274 ORDER BY pn.network_type, pn.nwid
275 ' . $limit);
276 }
277
278 public function getWebSite()
279 {
280 $site = $this->getNetworking(self::NETWORKING_WEB, 1);
281 if ($site->total() != 1) {
282 return null;
283 }
284 $site = $site->next();
285 return $site['address'];
286 }
287
288
e7b93962
FB
289 public function owner()
290 {
291 return User::getSilent($this);
292 }
293
b774ddab
FB
294 private static function fetchProfileData(array $pids)
295 {
296 if (count($pids) == 0) {
297 return array();
298 }
299 return XDB::fetchAllAssoc('SELECT p.*, p.sex = \'female\' AS sex, pe.entry_year, pe.grad_year,
300 pn_f.name AS firstname, pn_l.name AS lastname, pn_n.name AS nickname,
301 IF(pn_uf.name IS NULL, pn_f.name, pn_uf.name) AS firstname_usual,
302 IF(pn_ul.name IS NULL, pn_l.name, pn_ul.name) AS lastname_usual,
46e9eb99
FB
303 pd.promo AS promo, pd.short_name, pd.directory_name AS full_name,
304 pp.display_tel AS mobile, pp.pub AS mobile_pub
b774ddab
FB
305 FROM profiles AS p
306 INNER JOIN profile_display AS pd ON (pd.pid = p.pid)
307 INNER JOIN profile_education AS pe ON (pe.uid = p.pid AND FIND_IN_SET(\'primary\', pe.flags))
308 INNER JOIN profile_name AS pn_f ON (pn_f.pid = p.pid
309 AND pn_f.typeid = ' . self::getNameTypeId('lastname', true) . ')
310 INNER JOIN profile_name AS pn_l ON (pn_l.pid = p.pid
311 AND pn_l.typeid = ' . self::getNameTypeId('firstname', true) . ')
312 LEFT JOIN profile_name AS pn_uf ON (pn_uf.pid = p.pid
313 AND pn_uf.typeid = ' . self::getNameTypeId('lastname_ordinary', true) . ')
314 LEFT JOIN profile_name AS pn_ul ON (pn_ul.pid = p.pid
315 AND pn_ul.typeid = ' . self::getNameTypeId('firstname_ordinary', true) . ')
46e9eb99 316 LEFT JOIN profile_name AS pn_n ON (pn_n.pid = p.pid
b774ddab 317 AND pn_n.typeid = ' . self::getNameTypeId('nickname', true) . ')
46e9eb99 318 LEFT JOIN profile_phones AS pp ON (pp.uid = p.pid AND pp.link_type = \'user\' AND tel_type = \'mobile\')
b774ddab
FB
319 WHERE p.pid IN ' . XDB::formatArray($pids) . '
320 GROUP BY p.pid');
321 }
322
323 public static function getPID($login)
324 {
325 if ($login instanceof PlUser) {
326 return XDB::fetchOneCell('SELECT pid
327 FROM account_profiles
328 WHERE uid = {?} AND FIND_IN_SET(\'owner\', perms)',
329 $login->id());
330 } else if (ctype_digit($login)) {
331 return XDB::fetchOneCell('SELECT pid
332 FROM profiles
333 WHERE pid = {?}', $login);
334 } else {
335 return XDB::fetchOneCell('SELECT pid
336 FROM profiles
337 WHERE hrpid = {?}', $login);
338 }
339 }
340
341
e7b93962
FB
342 /** Return the profile associated with the given login.
343 */
a3118782
FB
344 public static function get($login)
345 {
b774ddab
FB
346 $pid = self::getPID($login);
347 if (!is_null($pid)) {
348 $data = self::fetchProfileData(array($pid));
349 return new Profile(array_pop($data));
350 } else {
efe597c5
FB
351 /* Let say we can identify a profile using the identifiers of its owner.
352 */
455ea0c9
FB
353 if (!($login instanceof PlUser)) {
354 $user = User::getSilent($login);
355 if ($user && $user->hasProfile()) {
356 return $user->profile();
357 }
efe597c5 358 }
3e53a496 359 return null;
e7b93962
FB
360 }
361 }
a3118782 362
b774ddab
FB
363 /** Return profiles for the list of pids.
364 */
365 public static function getBulkProfilesWithPIDs(array $pids)
366 {
367 if (count($pids) == 0) {
368 return array();
369 }
370 $data = self::fetchProfileData($pids);
371 $inv = array_flip($pids);
372 $profiles = array();
373 foreach ($data AS $p) {
374 $p = new Profile($p);
375 $key = $inv[$p->id()];
376 $profiles[$key] = $p;
377 }
378 return $profiles;
379 }
380
381 /** Return profiles for uids.
382 */
383 public static function getBulkProfilesWithUIDS(array $uids)
384 {
385 if (count($uids) == 0) {
386 return array();
387 }
388 $table = XDB::fetchAllAssoc('uid', 'SELECT ap.uid, ap.pid
389 FROM account_profiles AS ap
390 WHERE FIND_IN_SET(\'owner\', ap.perms)
391 AND ap.uid IN ' . XDB::formatArray($uids));
392 return self::getBulkProfilesWithPIDs($table);
393 }
394
a3118782
FB
395 public static function getNameTypeId($type, $for_sql = false)
396 {
397 if (!S::has('name_types')) {
eb6207f7 398 $table = XDB::fetchAllAssoc('type', 'SELECT id, type
32742f84 399 FROM profile_name_enum');
a3118782
FB
400 S::set('name_types', $table);
401 } else {
402 $table = S::v('name_types');
403 }
404 if ($for_sql) {
405 return XDB::escape($table[$type]);
406 } else {
407 return $table[$type];
408 }
409 }
e7b93962
FB
410}
411
412// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
413?>