Fix some errors on X.net.
[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'];
f74fb084
FB
64 if (!S::logged()) {
65 $this->setVisibilityLevel(self::VISIBILITY_PUBLIC);
66 }
e7b93962
FB
67 }
68
69 public function id()
70 {
71 return $this->pid;
72 }
73
74 public function hrid()
75 {
76 return $this->hrpid;
77 }
78
d5e60905
FB
79 public function promo()
80 {
81 return $this->promo;
82 }
83
94b72319
FB
84 /** Print a name with the given formatting:
85 * %s = • for women
86 * %f = firstname
87 * %l = lastname
88 * %F = fullname
89 * %S = shortname
90 * %p = promo
91 */
92 public function name($format)
93 {
94 return str_replace(array('%s', '%f', '%l', '%F', '%S', '%p'),
95 array($this->isFemale() ? '•' : '',
96 $this->first_name, $this->last_name,
97 $this->full_name, $this->short_name,
98 $this->promo), $format);
99 }
100
101 public function fullName($with_promo = false)
102 {
103 if ($with_promo) {
104 return $this->full_name . ' (' . $this->promo . ')';
105 }
106 return $this->full_name;
107 }
108
109 public function shortName($with_promo = false)
110 {
111 if ($with_promo) {
112 return $this->short_name . ' (' . $this->promo . ')';
113 }
114 return $this->short_name;
115 }
116
117 public function firstName()
118 {
08c91036 119 return $this->firstname;
94b72319
FB
120 }
121
122 public function lastName()
123 {
08c91036 124 return $this->lastname;
94b72319
FB
125 }
126
127 public function isFemale()
128 {
129 return $this->sex == PlUser::GENDER_FEMALE;
130 }
131
132 public function data()
133 {
134 $this->first_name;
135 return $this->data;
136 }
137
3e53a496
FB
138 public function __get($name)
139 {
140 if (property_exists($this, $name)) {
141 return $this->$name;
142 }
143
3e53a496
FB
144 if (isset($this->data[$name])) {
145 return $this->data[$name];
146 }
147
148 return null;
149 }
150
151 public function __isset($name)
152 {
153 return property_exists($this, $name) || isset($this->data[$name]);
154 }
155
f5642983
FB
156 public function setVisibilityLevel($visibility)
157 {
158 if ($visibility != self::VISIBILITY_PRIVATE
159 && $visibility != self::VISIBILITY_AX
160 && $visibility != self::VISIBILITY_PUBLIC) {
161 Platal::page()->kill("Visibility invalide: " . $visibility);
162 }
163 $this->visibility = self::$v_values[$visibility];
46e9eb99
FB
164 if ($this->mobile && !in_array($this->modbile_pub, $this->visibility)) {
165 unset($this->data['mobile']);
166 }
f5642983
FB
167 }
168
4bc5b8f0
FB
169
170 /* Addresses
171 */
172 public function getAddresses($flags, $limit = null)
f5642983
FB
173 {
174 $where = XDB::format('pa.pid = {?}', $this->id());
175 if ($flags & self::ADDRESS_MAIN) {
176 $where .= ' AND FIND_IN_SET(\'current\', pa.flags)';
177 }
178 if ($flags & self::ADDRESS_POSTAL) {
179 $where .= ' AND FIND_IN_SET(\'mail\', pa.flags)';
180 }
181 if ($this->visibility) {
182 $where .= ' AND pa.pub IN ' . XDB::formatArray($this->visibility);
183 }
184 $type = array();
185 if ($flags & self::ADDRESS_PRO) {
186 $type[] = 'job';
187 }
188 if ($flags & self::ADDRESS_PERSO) {
189 $type[] = 'home';
190 }
191 if (count($type) > 0) {
192 $where .= ' AND pa.type IN ' . XDB::formatArray($type);
193 }
4bc5b8f0 194 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
f5642983
FB
195 return XDB::iterator('SELECT pa.text, pa.postalCode, pa.type, pa.latitude, pa.longitude,
196 gl.name AS locality, gas.name AS subAdministrativeArea,
197 ga.name AS administrativeArea, gc.countryFR AS country,
198 FIND_IN_SET(\'current\', pa.flags) AS current,
199 FIND_IN_SET(\'temporary\', pa.flags) AS temporary,
200 FIND_IN_SET(\'secondary\', pa.flags) AS secondary,
201 FIND_IN_SET(\'mail\', pa.flags) AS mail, pa.type
202 FROM profile_addresses AS pa
203 LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId)
204 LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId)
205 LEFT JOIN geoloc_administrativeareas AS gas ON (gas.id = pa.subAdministrativeAreaId)
206 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId)
4bc5b8f0
FB
207 WHERE ' . $where . '
208 ORDER BY pa.id
209 ' . $limit);
f5642983
FB
210 }
211
212 public function getMainAddress()
213 {
214 $it = $this->getAddresses(self::ADDRESS_PERSO | self::ADDRESS_MAIN);
215 if ($it->total() == 0) {
216 return null;
217 } else {
218 return $it->next();
219 }
220 }
3e53a496 221
4bc5b8f0
FB
222
223 /* Educations
224 */
225 public function getEducations($flags, $limit = null)
226 {
227 $where = XDB::format('pe.uid = {?}', $this->id());
228 if ($flags & self::EDUCATION_MAIN) {
229 $where .= ' AND FIND_IN_SET(\'primary\', pe.flags)';
230 } else if ($flags & self::EDUCATION_EXTRA) {
231 $where .= ' AND NOT FIND_IN_SET(\'primary\', pe.flags)';
232 } else if ($flags & self::EDUCATION_FINISHED) {
233 $where .= ' AND pe.grad_year <= YEAR(CURDATE())';
234 } else if ($flags & self::EDUCATION_CURRENT) {
235 $where .= ' AND pe.grad_year > YEAR(CURDATE())';
236 }
237 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
238 return XDB::iterator('SELECT pe.entry_year, pe.grad_year, pe.program,
239 pee.name AS school, pee.abbreviation AS school_short, pee.url AS school_url, gc.countryFR AS country,
240 pede.degree, pede.abbreviation AS degree_short, pede.level AS degree_level, pefe.field,
241 FIND_IN_SET(\'primary\', pe.flags) AS prim
242 FROM profile_education AS pe
243 INNER JOIN profile_education_enum AS pee ON (pe.eduid = pee.id)
244 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pee.country)
245 INNER JOIN profile_education_degree_enum AS pede ON (pe.degreeid = pede.id)
246 LEFT JOIN profile_education_field_enum AS pefe ON (pe.fieldid = pefe.id)
247 WHERE ' . $where . '
248 ORDER BY NOT FIND_IN_SET(\'primary\', pe.flags), pe.entry_year, pe.id
249 ' . $limit);
250 }
251
252 public function getExtraEducations($limit = null)
253 {
254 return $this->getEducations(self::EDUCATION_EXTRA, $limit);
255 }
256
257
04a94b1d
FB
258 /** Networking
259 */
260
261 public function getNetworking($flags, $limit = null)
262 {
263 $where = XDB::format('pn.uid = {?}', $this->id());
264 if ($flags & self::NETWORKING_WEB) {
265 $where .= ' AND pn.network_type = 0'; // XXX hardcoded reference to web site index
266 }
267 if ($this->visibility) {
268 $where .= ' AND pn.pub IN ' . XDB::formatArray($this->visibility);
269 }
270 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
271 return XDB::iterator('SELECT pne.name, pne.icon,
272 IF (LENGTH(pne.link) > 0, REPLACE(pne.link, \'%s\', pn.address),
273 pn.address) AS address
274 FROM profile_networking AS pn
275 INNER JOIN profile_networking_enum AS pne ON (pn.network_type = pne.network_type)
276 WHERE ' . $where . '
277 ORDER BY pn.network_type, pn.nwid
278 ' . $limit);
279 }
280
281 public function getWebSite()
282 {
283 $site = $this->getNetworking(self::NETWORKING_WEB, 1);
284 if ($site->total() != 1) {
285 return null;
286 }
287 $site = $site->next();
288 return $site['address'];
289 }
290
291
e718bd18
FB
292 /** Jobs
293 */
294
295 public function getJobs($flags, $limit = null)
296 {
297 $where = XDB::format('pj.uid = {?}', $this->id());
298 $cond = 'TRUE';
299 if ($this->visibility) {
300 $where .= ' AND pj.pub IN ' . XDB::formatArray($this->visibility);
301 $cond = 'pj.email_pub IN ' . XDB::formatArray($this->visibility);
302 }
303 $limit = is_null($limit) ? '' : XDB::format('LIMIT {?}', (int)$limit);
304 return XDB::iterator('SELECT pje.name, pje.acronym, pje.url, pje.email, pje.NAF_code,
305 pj.description, pj.url AS user_site,
306 IF (' . $cond . ', pj.email, NULL) AS user_email,
83ff5281
SJ
307 pjse.name AS sector, pjsse.name AS subsector,
308 pjssse.name AS subsubsector
e718bd18
FB
309 FROM profile_job AS pj
310 INNER JOIN profile_job_enum AS pje ON (pje.id = pj.jobid)
e718bd18
FB
311 LEFT JOIN profile_job_sector_enum AS pjse ON (pjse.id = pj.sectorid)
312 LEFT JOIN profile_job_subsector_enum AS pjsse ON (pjsse.id = pj.subsectorid)
313 LEFT JOIN profile_job_subsubsector_enum AS pjssse ON (pjssse.id = pj.subsubsectorid)
314 WHERE ' . $where . '
315 ORDER BY pj.id
316 ' . $limit);
317 }
318
319 public function getMailJob()
320 {
321 $job = $this->getJobs(self::JOBS_MAIN, 1);
322 if ($job->total() != 1) {
323 return null;
324 }
325 return $job->next();
326 }
327
328
e7b93962
FB
329 public function owner()
330 {
331 return User::getSilent($this);
332 }
333
b774ddab
FB
334 private static function fetchProfileData(array $pids)
335 {
336 if (count($pids) == 0) {
337 return array();
338 }
339 return XDB::fetchAllAssoc('SELECT p.*, p.sex = \'female\' AS sex, pe.entry_year, pe.grad_year,
340 pn_f.name AS firstname, pn_l.name AS lastname, pn_n.name AS nickname,
341 IF(pn_uf.name IS NULL, pn_f.name, pn_uf.name) AS firstname_usual,
342 IF(pn_ul.name IS NULL, pn_l.name, pn_ul.name) AS lastname_usual,
46e9eb99
FB
343 pd.promo AS promo, pd.short_name, pd.directory_name AS full_name,
344 pp.display_tel AS mobile, pp.pub AS mobile_pub
b774ddab
FB
345 FROM profiles AS p
346 INNER JOIN profile_display AS pd ON (pd.pid = p.pid)
347 INNER JOIN profile_education AS pe ON (pe.uid = p.pid AND FIND_IN_SET(\'primary\', pe.flags))
348 INNER JOIN profile_name AS pn_f ON (pn_f.pid = p.pid
767025be 349 AND pn_f.typeid = ' . self::getNameTypeId('firstname', true) . ')
b774ddab 350 INNER JOIN profile_name AS pn_l ON (pn_l.pid = p.pid
767025be 351 AND pn_l.typeid = ' . self::getNameTypeId('lastname', true) . ')
b774ddab 352 LEFT JOIN profile_name AS pn_uf ON (pn_uf.pid = p.pid
767025be 353 AND pn_uf.typeid = ' . self::getNameTypeId('firstname_ordinary', true) . ')
b774ddab 354 LEFT JOIN profile_name AS pn_ul ON (pn_ul.pid = p.pid
767025be 355 AND pn_ul.typeid = ' . self::getNameTypeId('lastname_ordinary', true) . ')
46e9eb99 356 LEFT JOIN profile_name AS pn_n ON (pn_n.pid = p.pid
b774ddab 357 AND pn_n.typeid = ' . self::getNameTypeId('nickname', true) . ')
46e9eb99 358 LEFT JOIN profile_phones AS pp ON (pp.uid = p.pid AND pp.link_type = \'user\' AND tel_type = \'mobile\')
b774ddab
FB
359 WHERE p.pid IN ' . XDB::formatArray($pids) . '
360 GROUP BY p.pid');
361 }
362
363 public static function getPID($login)
364 {
365 if ($login instanceof PlUser) {
366 return XDB::fetchOneCell('SELECT pid
367 FROM account_profiles
368 WHERE uid = {?} AND FIND_IN_SET(\'owner\', perms)',
369 $login->id());
370 } else if (ctype_digit($login)) {
371 return XDB::fetchOneCell('SELECT pid
372 FROM profiles
373 WHERE pid = {?}', $login);
374 } else {
375 return XDB::fetchOneCell('SELECT pid
376 FROM profiles
377 WHERE hrpid = {?}', $login);
378 }
379 }
380
381
e7b93962
FB
382 /** Return the profile associated with the given login.
383 */
a3118782
FB
384 public static function get($login)
385 {
b774ddab
FB
386 $pid = self::getPID($login);
387 if (!is_null($pid)) {
388 $data = self::fetchProfileData(array($pid));
389 return new Profile(array_pop($data));
390 } else {
efe597c5
FB
391 /* Let say we can identify a profile using the identifiers of its owner.
392 */
455ea0c9
FB
393 if (!($login instanceof PlUser)) {
394 $user = User::getSilent($login);
395 if ($user && $user->hasProfile()) {
396 return $user->profile();
397 }
efe597c5 398 }
3e53a496 399 return null;
e7b93962
FB
400 }
401 }
a3118782 402
b774ddab
FB
403 /** Return profiles for the list of pids.
404 */
405 public static function getBulkProfilesWithPIDs(array $pids)
406 {
407 if (count($pids) == 0) {
408 return array();
409 }
410 $data = self::fetchProfileData($pids);
411 $inv = array_flip($pids);
412 $profiles = array();
413 foreach ($data AS $p) {
414 $p = new Profile($p);
415 $key = $inv[$p->id()];
416 $profiles[$key] = $p;
417 }
418 return $profiles;
419 }
420
421 /** Return profiles for uids.
422 */
423 public static function getBulkProfilesWithUIDS(array $uids)
424 {
425 if (count($uids) == 0) {
426 return array();
427 }
428 $table = XDB::fetchAllAssoc('uid', 'SELECT ap.uid, ap.pid
429 FROM account_profiles AS ap
430 WHERE FIND_IN_SET(\'owner\', ap.perms)
431 AND ap.uid IN ' . XDB::formatArray($uids));
432 return self::getBulkProfilesWithPIDs($table);
433 }
434
a3118782
FB
435 public static function getNameTypeId($type, $for_sql = false)
436 {
437 if (!S::has('name_types')) {
eb6207f7 438 $table = XDB::fetchAllAssoc('type', 'SELECT id, type
32742f84 439 FROM profile_name_enum');
a3118782
FB
440 S::set('name_types', $table);
441 } else {
442 $table = S::v('name_types');
443 }
444 if ($for_sql) {
445 return XDB::escape($table[$type]);
446 } else {
447 return $table[$type];
448 }
449 }
e7b93962
FB
450}
451
452// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
453?>