b1f0f59e7e5af55435c169fd73f5a54a2a32dc70
[platal.git] / include / profilefields.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2010 Polytechnique.org *
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
22 // {{{ class ProfileField
23 /** To store a "field" from the profile
24 * Provides functions for loading a batch of such data
25 */
26 abstract class ProfileField
27 {
28 /** The profile to which this field belongs
29 */
30 public $pid;
31
32 /** Fetches data from the database for the given pids, compatible with
33 * the visibility context.
34 * @param $pids An array of pids
35 * @param $visibility The level of visibility fetched fields must have
36 * @return a PlIterator yielding data suitable for a "new ProfileBlah($data)"
37 */
38 abstract public static function fetchData(array $pids, $visibility);
39
40 public static function buildForPID($cls, $pid, $visibility)
41 {
42 $res = self::buildFromPIDs($cls, array($pid), $visibility);
43 return array_pop($res);
44 }
45
46 /** Build a list of ProfileFields from a set of pids
47 * @param $cls The name of the field to create ('ProfileMedals', ...)
48 * @param $pids An array of pids
49 * @param $visibility An array of allowed visibility contexts
50 * @return An array of $pid => ProfileField
51 */
52 public static function buildFromPIDs($cls, array $pids, $visibility)
53 {
54 $it = new ProfileFieldIterator($cls, $pids, $visibility);
55 $res = array();
56 while ($pf = $it->next()) {
57 $res[$pf->pid] = $pf;
58 }
59 return $res;
60 }
61
62 public static function getForPID($cls, $pid, $visibility)
63 {
64 $it = new ProfileFieldIterator($cls, array($pid), $visibility);
65 return $it->next();
66 }
67 }
68 // }}}
69
70 // {{{ class ProfileFieldIterator
71 class ProfileFieldIterator implements PlIterator
72 {
73 private $data;
74 private $cls;
75
76 public function __construct($cls, array $pids, $visibility)
77 {
78 $this->data = call_user_func(array($cls, 'fetchData'), $pids, $visibility);
79 $this->cls = $cls;
80 }
81
82 public function next()
83 {
84 $d = $this->data->next();
85 if ($d == null) {
86 return null;
87 } else {
88 $cls = $this->cls;
89 return new $cls($d);
90 }
91 }
92
93 public function total()
94 {
95 return $this->data->total();
96 }
97
98 public function first()
99 {
100 return $this->data->first();
101 }
102
103 public function last()
104 {
105 return $this->data->last();
106 }
107 }
108 // }}}
109
110 // {{{ class Phone
111 class Phone
112 {
113 const TYPE_FAX = 'fax';
114 const TYPE_FIXED = 'fixed';
115 const TYPE_MOBILE = 'mobile';
116 public $type;
117
118 public $search;
119 public $display;
120 public $comment = '';
121
122 const LINK_JOB = 'job';
123 const LINK_ADDRESS = 'address';
124 const LINK_PROFILE = 'user';
125 const LINK_COMPANY = 'hq';
126 public $link_type;
127 public $link_id;
128
129 /** Fields are :
130 * $type, $search, $display, $link_type, $link_id, $comment, $pid, $id
131 */
132 public function __construct($data)
133 {
134 foreach ($data as $key => $val) {
135 $this->$key = $val;
136 }
137 }
138 }
139 // }}}
140 // {{{ class Company
141 class Company
142 {
143 public $id;
144 public $name;
145 public $acronym;
146 public $url;
147 public $phone = null;
148 public $address = null;
149
150 /** Fields are:
151 * $id, $name, $acronym, $url
152 */
153 public function __construct($data)
154 {
155 foreach ($data as $key => $val) {
156 $this->$key = $val;
157 }
158 }
159
160 public function setPhone(Phone &$phone)
161 {
162 if ($phone->link_type == Phone::LINK_COMPANY && $phone->link_id == $this->id) {
163 $this->phone = $phone;
164 }
165 }
166
167 public function setAddress(Address &$address)
168 {
169 if ($address->link_type == Address::LINK_COMPANY && $address->link_id == $this->id) {
170 $this->address = $address;
171 }
172 }
173
174 }
175 // }}}
176 // {{{ class Job
177 class Job
178 {
179 public $pid;
180 public $id;
181
182 private $company = null;
183 private $phones = array();
184 private $address = null;
185
186 public $company_id;
187
188 public $description;
189 public $url;
190 public $email;
191
192 /** Fields are:
193 * pid, id, company_id, description, url, email
194 */
195 public function __construct($data)
196 {
197 foreach ($data as $key => $val) {
198 $this->$key = $val;
199 }
200 $this->setCompany(CompanyList::get($this->jobid));
201 }
202
203 public function phones()
204 {
205 return $this->phones;
206 }
207
208 public function company()
209 {
210 return $this->company;
211 }
212
213 public function addPhone(Phone &$phone)
214 {
215 if ($phone->link_type == Phone::LINK_JOB && $phone->link_id == $this->id && $phone->pid == $this->pid) {
216 $this->phones[] = $phone;
217 }
218 }
219
220 public function setAddress(Address $address)
221 {
222 if ($address->link_id == Address::LINK_JOB && $address->link_id == $this->id && $address->pid == $this->pid) {
223 $this->address = $address;
224 }
225 }
226
227 public function setCompany(Company $company)
228 {
229 $this->company = $company;
230 }
231 }
232 // }}}
233 // {{{ class Address
234 class Address
235 {
236 const LINK_JOB = 'job';
237 const LINK_COMPANY = 'hq';
238 const LINK_PROFILE = 'home';
239
240 public $link_id;
241 public $link_type;
242
243 public $flags;
244 public $text;
245 public $postalCode;
246 public $country;
247
248 private $phones = array();
249
250 /** Fields are:
251 * pîd, id, link_id, link_type, flags, text, postcode, country
252 */
253 public function __construct($data)
254 {
255 foreach ($data as $key => $val) {
256 $this->$key = $val;
257 }
258 }
259
260 public function addPhone(Phone &$phone)
261 {
262 if ($phone->link_type == Phone::LINK_ADDRESS && $phone->link_id == $this->id && $phone->pid == $this->pid) {
263 $this->phones[] = $phone;
264 }
265 }
266
267 public function phones()
268 {
269 return $this->phones;
270 }
271
272 public function hasFlags($flags)
273 {
274 return $flags & $this->flags;
275 }
276 }
277 // }}}
278 // {{{ class Education
279 class Education
280 {
281 public $eduid;
282 public $degreeid;
283 public $fieldid;
284
285 public $entry_year;
286 public $grad_year;
287 public $program;
288 public $flags;
289
290 public function __construct(array $data)
291 {
292 $this->eduid = $data['eduid'];
293 $this->degreeid = $data['degreeid'];
294 $this->fieldid = $data['fieldid'];
295
296 $this->entry_year = $data['entry_year'];
297 $this->grad_year = $data['grad_year'];
298 $this->program = $data['program'];
299 $this->flags = new PlFlagSet($data['flags']);
300 }
301 }
302 // }}}
303
304 // {{{ class ProfileEducation [ Field ]
305 class ProfileEducation extends ProfileField
306 {
307 private $educations = array();
308
309 public function __construct(PlIterator $it)
310 {
311 $this->pid = $it->value();
312 $this->visibility = Profile::VISIBILITY_PUBLIC;
313 while ($edu = $it->next()) {
314 $this->educations[$edu['id']] = new Education($edu);
315 }
316 }
317
318 public function get($flags, $limit)
319 {
320 $educations = array();
321 $year = getdate();
322 $year = $year['year'];
323 $nb = 0;
324 foreach ($this->educations as $id => $edu) {
325 if (
326 (($flags & Profile::EDUCATION_MAIN) && $edu->flags->hasFlag('primary'))
327 ||
328 (($flags & Profile::EDUCATION_EXTRA) && !$edu->flags->hasFlag('primary'))
329 ||
330 (($flags & Profile::EDUCATION_FINISHED) && $edu->grad_year <= $year)
331 ||
332 (($flags & Profile::EDUCATION_CURRENT) && $edu->grad_year > $year)
333 ) {
334 $educations[$id] = $edu;
335 ++$nb;
336 }
337 if ($limit != null && $nb >= $limit) {
338 break;
339 }
340 }
341 return PlIteratorUtils::fromArray($educations);
342 }
343
344 public static function fetchData(array $pids, $visibility)
345 {
346 $data = XDB::iterator('SELECT id, pid, eduid, degreeid, fieldid,
347 entry_year, grad_year, program, flags
348 FROM profile_education
349 WHERE pid IN {?}
350 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
351 NOT FIND_IN_SET(\'primary\', flags), entry_year, id',
352 $pids);
353
354 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
355 }
356 }
357 // }}}
358 // {{{ class ProfileMedals [ Field ]
359 class ProfileMedals extends ProfileField
360 {
361 public $medals = array();
362
363 public function __construct(PlIterator $it)
364 {
365 while ($medal = $it->next()) {
366 $this->medals[$medal['mid']] = $medal['gid'];
367 }
368 }
369
370 public static function fetchData(array $pids, $visibility)
371 {
372 $data = XDB::iterator('SELECT pm.pid, pm.mid, pm.gid
373 FROM profile_medals AS pm
374 LEFT JOIN profiles AS p ON (pm.pid = p.pid)
375 WHERE pm.pid IN {?} AND p.medals_pub IN {?}
376 ORDER BY ' . XDB::formatCustomOrder('pm.pid', $pids),
377 XDB::formatArray($pids),
378 XDB::formatArray($visibility)
379 );
380
381 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
382 }
383 }
384 // }}}
385 // {{{ class ProfileNetworking [ Field ]
386 class ProfileNetworking extends ProfileField
387 {
388 private $networks = array();
389
390 public function __construct(PlIterator $it)
391 {
392 while ($network = $it->next()) {
393 $this->networks[$network['nwid']] = $network['address'];
394 }
395 }
396
397 public static function fetchData(array $pids, $visibility)
398 {
399 $data = XDB::iterator('SELECT pid, nwid, address, network_type
400 FROM profile_networking
401 WHERE pid IN {?} AND pub IN {?}
402 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
403 network_type, nwid',
404 $pids, $visibility);
405
406 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
407 }
408
409 public function get($flags, $limit = null)
410 {
411 $nws = array();
412 $nb = 0;
413 foreach ($this->networks as $id => $nw) {
414 // XXX hardcoded reference to web site index
415 if (
416 (($flags & self::NETWORKING_WEB) && $nw['network_type'] == 0)
417 ||
418 (! ($flags & self::NETWORKING_WEB))
419 ) {
420 $nws[$id] = $nw;
421 ++$nb;
422 }
423 if ($nb >= $limit) {
424 break;
425 }
426 }
427 return PlIteratorUtils::fromArray($nws);
428 }
429 }
430 // }}}
431 // {{{ class ProfilePhoto [ Field ]
432 class ProfilePhoto extends ProfileField
433 {
434 public $pic;
435
436 public function __construct(array $data)
437 {
438 if ($data == null || count($data) == 0) {
439 $this->pic = null;
440 } else {
441 $this->pid = $data['pid'];
442 $this->pic = PlImage::fromDATA($data['attach'],
443 $data['attachmime'],
444 $data['x'],
445 $data['y']);
446 }
447 }
448
449 public static function fetchData(array $pids, $visibility)
450 {
451 $data = XDB::iterator('SELECT *
452 FROM profile_photos
453 WHERE pid IN {?} AND attachmime IN (\'jpeg\', \'png\') AND pub IN {?}
454 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
455 $pids, $visibility);
456
457 return $data;
458 }
459 }
460 // }}}
461 // {{{ class ProfileCorps [ Field ]
462 class ProfileCorps extends ProfileField
463 {
464 public $original;
465 public $current;
466 public $rank;
467
468 public function __construct(array $data)
469 {
470 $this->original = $data['original_corpsid'];
471 $this->current = $data['current_corpsid'];
472 $this->rank = $data['rankid'];
473 $this->visibility = $data['corps_pub'];
474 }
475
476 public static function fetchData(array $pids, $visibility)
477 {
478 $data = XDB::iterator('SELECT pid, original_corpsid, current_corpsid,
479 rankid
480 FROM profile_corps
481 WHERE pid IN {?} AND corps_pub IN {?}
482 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
483 XDB::formatArray($pids),
484 XDB::formatArray($visibility)
485 );
486
487 return $data;
488 }
489 }
490 // }}}
491
492 /** Loading of data for a Profile :
493 * 1) load jobs, addresses, phones
494 * 2) attach phones to addresses, jobs and profiles
495 * 3) attach addresses to jobs and profiles
496 */
497
498 // {{{ class ProfileAddresses [ Field ]
499 class ProfileAddresses extends ProfileField
500 {
501 private $addresses = array();
502
503 public function __construct(PlIterator $it)
504 {
505 if ($it instanceof PlInnerSubIterator) {
506 $this->pid = $it->value();
507 }
508
509 while ($addr = $it->next()) {
510 $this->addresses[] = new Address($addr);
511 }
512 }
513
514 public function get($flags, $limit = null)
515 {
516 $res = array();
517 $nb = 0;
518 foreach ($this->addresses as $addr) {
519 if ($addr->hasFlags($flags)) {
520 $res[] = $addr;
521 $nb++;
522 }
523 if ($limit != null && $nb == $limit) {
524 break;
525 }
526 }
527 return PlIteratorUtils::fromArray($res);
528 }
529
530 public static function fetchData(array $pids, $visibility)
531 {
532 $data = XDB::iterator('SELECT pid, text, postalCode, type, latitude, longitude,
533 flags, type
534 FROM profile_addresses
535 WHERE pid in {?} AND pub IN {?}
536 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
537 $pids, $visibility);
538
539 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
540 }
541
542 public function addPhones(ProfilePhones $phones)
543 {
544 $p = $phones->get(0);
545 while ($phone = $p->next()) {
546 if ($phone->link_type == Phone::LINK_ADDRESS && array_key_exists($phone->link_id, $this->addresses)) {
547 $this->addresses[$phone->link_id]->addPhone($phone);
548 }
549 }
550 }
551 }
552 // }}}
553 // {{{ class ProfilePhones [ Field ]
554 class ProfilePhones extends ProfileField
555 {
556 private $phones = array();
557
558 public function __construct(PlIterator $phones)
559 {
560 while ($phone = $it->next()) {
561 $this->phones[] = Phone::buildFromData($phone);
562 }
563 }
564
565 public function get($flags, $limit = null)
566 {
567 $phones = array();
568 $nb = 0;
569 foreach ($this->phones as $id => $phone) {
570 $phones[$id] = $phone;
571 ++$nb;
572 if ($limit != null && $nb == $limit) {
573 break;
574 }
575 }
576 return PlIteratorUtils::fromArray($phones);
577 }
578
579 public static function fetchData(array $pids, $visibility)
580 {
581 $data = XDB::iterator('SELECT type, search, display, link_type, comment
582 FROM profile_phones
583 WHERE pid IN {?} AND pub IN {?}
584 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
585 XDB::formatArray($pids),
586 XDB::formatArray($visibility)
587 );
588 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
589 }
590 }
591 // }}}
592 // {{{ class ProfileJobs [ Field ]
593 class ProfileJobs extends ProfileField
594 {
595 private $jobs = array();
596
597 public function __construct(PlIterator $jobs)
598 {
599 while ($job = $jobs->next()) {
600 $this->jobs[$job['id']] = new Job($job);
601 }
602 }
603
604 public static function fetchData(array $pids, $visibility)
605 {
606 $data = XDB::iterator('SELECT id, pid, description, url,
607 jobid, sectorid, subsectorid, subsubsectorid,
608 IF(email_pub IN {?}, email, NULL) AS email
609 FROM profile_job
610 WHERE pid IN {?} AND pub IN {?}
611 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
612 id',
613 $visibility, $pids, $visibility);
614 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
615 }
616
617 public function get($flags, $limit = null)
618 {
619 $jobs = array();
620 $nb = 0;
621 foreach ($this->jobs as $id => $job) {
622 $jobs[$id] = $job;
623 ++$nb;
624 if ($limit != null && $nb >= $limit) {
625 break;
626 }
627 }
628 return PlIteratorUtils::fromArray($jobs);
629 }
630
631 public function addPhones(ProfilePhones $phones)
632 {
633 $p = $phones->get(0);
634 while ($phone = $p->next()) {
635 if ($phone->link_type == Phone::LINK_JOB && array_key_exists($phone->link_id, $this->jobs)) {
636 $this->jobs[$phone->link_id]->addPhones($phone);
637 }
638 }
639 }
640
641 public static function addAddresses(ProfileAddresses $addresses)
642 {
643 $a = $addresses->get(Profile::ADDRESS_PRO);
644 while ($address = $a->next()) {
645 if ($address->link_type == Address::LINK_JOB && array_key_exists($address->link_id, $this->jobs)) {
646 $this->jobs[$address->link_id]->setAddress($address);
647 }
648 }
649 }
650
651 public static function addCompanies(array $companies)
652 {
653 foreach ($this->jobs as $job)
654 {
655 $job->setCompany($companies[$job->company_id]);
656 }
657 }
658 }
659 // }}}
660
661 // {{{ class CompanyList
662 class CompanyList
663 {
664 static private $fullload = false;
665 static private $companies = array();
666
667 static public function preload($pids = array())
668 {
669 if (self::$fullload) {
670 return;
671 }
672 // Load raw data
673 if (count($pids)) {
674 $join = 'LEFT JOIN profile_jobs ON (profile_job.jobid = profile_job_enum.id)';
675 $where = 'profile_jobs.pid IN ' . XDB::formatArray($pids);
676 } else {
677 $join = '';
678 $where = '';
679 }
680
681 $it = XDB::iterator('SELECT pje.id, pje.name, pje.acronym, pje.url,
682 pa.flags, pa.text, pa.postalCode, pa.countryId,
683 pa.type, pa.pub
684 FROM profile_job_enum AS pje
685 LEFT JOIN profile_addresses AS pa ON (pje.id = pa.jobid AND pa.type = \'hq\')
686 ' . $join . '
687 ' . $where);
688 while ($row = $it->next()) {
689 $cp = new Company($row);
690 $addr = new Address($row);
691 $cp->setAddress($addr);
692 self::$companies[$row['id']] = $cp;
693 }
694
695 // TODO: add phones to addresses
696 if (count($pids) == 0) {
697 self::$fullload = true;
698 }
699 }
700
701 static public function get($id)
702 {
703 if (!array_key_exists($id, self::$companies)) {
704 self::preload();
705 }
706 return self::$companies[$id];
707 }
708 }
709
710 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
711 ?>