b8a209826cc91676cf5b0d9a7df7fe7464532fd2
[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($date)
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 }
201
202 public function phones()
203 {
204 return $this->phones;
205 }
206
207 public function company()
208 {
209 return $this->company;
210 }
211
212 public function addPhone(Phone &$phone)
213 {
214 if ($phone->link_type == Phone::LINK_JOB && $phone->link_id == $this->id && $phone->pid == $this->pid) {
215 $this->phones[] = $phone;
216 }
217 }
218
219 public function setAddress(Address $address)
220 {
221 if ($address->link_id == Address::LINK_JOB && $address->link_id == $this->id && $address->pid == $this->pid) {
222 $this->address = $address;
223 }
224 }
225
226 public function setCompany(Company $company)
227 {
228 $this->company = $company;
229 }
230 }
231 // }}}
232 // {{{ class Address
233 class Address
234 {
235 const LINK_JOB = 'job';
236 const LINK_COMPANY = 'hq';
237 const LINK_PROFILE = 'home';
238
239 public $link_id;
240 public $link_type;
241
242 public $flags;
243 public $text;
244 public $postcode;
245 public $country;
246
247 private $phones = array();
248
249 /** Fields are:
250 * pîd, id, link_id, link_type, flags, text, postcode, country
251 */
252 public function __construct($data)
253 {
254 foreach ($data as $key => $val) {
255 $this->$key = $val;
256 }
257 }
258
259 public function addPhone(Phone &$phone)
260 {
261 if ($phone->link_type == Phone::LINK_ADDRESS && $phone->link_id == $this->id && $phone->pid == $this->pid) {
262 $this->phones[] = $phone;
263 }
264 }
265
266 public function phones()
267 {
268 return $this->phones;
269 }
270
271 public function hasFlags($flags)
272 {
273 return $flags & $this->flags;
274 }
275 }
276 // }}}
277 // {{{ class Education
278 class Education
279 {
280 public $eduid;
281 public $degreeid;
282 public $fieldid;
283
284 public $entry_year;
285 public $grad_year;
286 public $program;
287 public $flags;
288
289 public function __construct(array $data)
290 {
291 $this->eduid = $data['eduid'];
292 $this->degreeid = $data['degreeid'];
293 $this->fieldid = $data['fieldid'];
294
295 $this->entry_year = $data['entry_year'];
296 $this->grad_year = $data['grad_year'];
297 $this->program = $data['program'];
298 $this->flags = new PlFlagSet($data['flags']);
299 }
300 }
301 // }}}
302
303 // {{{ class ProfileEducation [ Field ]
304 class ProfileEducation extends ProfileField
305 {
306 private $educations = array();
307
308 public function __construct(PlIterator $it)
309 {
310 $this->pid = $it->value();
311 $this->visibility = Profile::VISIBILITY_PUBLIC;
312 while ($edu = $it->next()) {
313 $this->educations[$edu['id']] = new Education($edu);
314 }
315 }
316
317 public function get($flags, $limit)
318 {
319 $educations = array();
320 $year = getdate();
321 $year = $year['year'];
322 $nb = 0;
323 foreach ($this->educations as $id => $edu) {
324 if (
325 (($flags & Profile::EDUCATION_MAIN) && $edu->flags->hasFlag('primary'))
326 ||
327 (($flags & Profile::EDUCATION_EXTRA) && !$edu->flags->hasFlag('primary'))
328 ||
329 (($flags & Profile::EDUCATION_FINISHED) && $edu->grad_year <= $year)
330 ||
331 (($flags & Profile::EDUCATION_CURRENT) && $edu->grad_year > $year)
332 ) {
333 $educations[$id] = $edu;
334 ++$nb;
335 }
336 if ($limit != null && $nb >= $limit) {
337 break;
338 }
339 }
340 return PlIteratorUtils::fromArray($educations);
341 }
342
343 public static function fetchData(array $pids, $visibility)
344 {
345 $data = XDB::iterator('SELECT id, pid, eduid, degreeid, fieldid,
346 entry_year, grad_year, program, flags
347 FROM profile_education
348 WHERE pid IN {?}
349 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
350 NOT FIND_IN_SET(\'primary\', flags), entry_year, id',
351 $pids);
352
353 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
354 }
355 }
356 // }}}
357 // {{{ class ProfileMedals [ Field ]
358 class ProfileMedals extends ProfileField
359 {
360 public $medals = array();
361
362 public function __construct(PlIterator $it)
363 {
364 while ($medal = $it->next()) {
365 $this->medals[$medal['mid']] = $medal['gid'];
366 }
367 }
368
369 public static function fetchData(array $pids, $visibility)
370 {
371 $data = XDB::iterator('SELECT pm.pid, pm.mid, pm.gid
372 FROM profile_medals AS pm
373 LEFT JOIN profiles AS p ON (pm.pid = p.pid)
374 WHERE pm.pid IN {?} AND p.medals_pub IN {?}
375 ORDER BY ' . XDB::formatCustomOrder('pm.pid', $pids),
376 XDB::formatArray($pids),
377 XDB::formatArray($visibility)
378 );
379
380 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
381 }
382 }
383 // }}}
384 // {{{ class ProfileNetworking [ Field ]
385 class ProfileNetworking extends ProfileField
386 {
387 private $networks = array();
388
389 public function __construct(PlIterator $it)
390 {
391 while ($network = $it->next()) {
392 $this->networks[$network['nwid']] = $network['address'];
393 }
394 }
395
396 public static function fetchData(array $pids, $visibility)
397 {
398 $data = XDB::iterator('SELECT pid, nwid, address, network_type
399 FROM profile_networking
400 WHERE pid IN {?} AND pub IN {?}
401 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
402 network_type, nwid',
403 $pids, $visibility);
404
405 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
406 }
407
408 public function get($flags, $limit = null)
409 {
410 $nws = array();
411 $nb = 0;
412 foreach ($this->networks as $id => $nw) {
413 // XXX hardcoded reference to web site index
414 if (
415 (($flags & self::NETWORKING_WEB) && $nw['network_type'] == 0)
416 ||
417 (! ($flags & self::NETWORKING_WEB))
418 ) {
419 $nws[$id] = $nw;
420 ++$nb;
421 }
422 if ($nb >= $limit) {
423 break;
424 }
425 }
426 return PlIteratorUtils::fromArray($nws);
427 }
428 }
429 // }}}
430 // {{{ class ProfilePhoto [ Field ]
431 class ProfilePhoto extends ProfileField
432 {
433 public $pic;
434
435 public function __construct(array $data)
436 {
437 if ($data == null || count($data) == 0) {
438 $this->pic = null;
439 } else {
440 $this->pid = $data['pid'];
441 $this->pic = PlImage::fromDATA($data['attach'],
442 $data['attachmime'],
443 $data['x'],
444 $data['y']);
445 }
446 }
447
448 public static function fetchData(array $pids, $visibility)
449 {
450 $data = XDB::iterator('SELECT *
451 FROM profile_photos
452 WHERE pid IN {?} AND attachmime IN (\'jpeg\', \'png\') AND pub IN {?}
453 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
454 $pids, $visibility);
455
456 return $data;
457 }
458 }
459 // }}}
460 // {{{ class ProfileCorps [ Field ]
461 class ProfileCorps extends ProfileField
462 {
463 public $original;
464 public $current;
465 public $rank;
466
467 public function __construct(array $data)
468 {
469 $this->original = $data['original_corpsid'];
470 $this->current = $data['current_corpsid'];
471 $this->rank = $data['rankid'];
472 $this->visibility = $data['corps_pub'];
473 }
474
475 public static function fetchData(array $pids, $visibility)
476 {
477 $data = XDB::iterator('SELECT pid, original_corpsid, current_corpsid,
478 rankid
479 FROM profile_corps
480 WHERE pid IN {?} AND corps_pub IN {?}
481 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
482 XDB::formatArray($pids),
483 XDB::formatArray($visibility)
484 );
485
486 return $data;
487 }
488 }
489 // }}}
490
491 /** Loading of data for a Profile :
492 * 1) load jobs, addresses, phones
493 * 2) attach phones to addresses, jobs and profiles
494 * 3) attach addresses to jobs and profiles
495 */
496
497 // {{{ class ProfileAddresses [ Field ]
498 class ProfileAddresses extends ProfileField
499 {
500 private $addresses = array();
501
502 public function __construct(PlIterator $it)
503 {
504 if ($it instanceof PlInnerSubIterator) {
505 $this->pid = $it->value();
506 }
507
508 while ($addr = $it->next()) {
509 $this->addresses[] = new Address($addr);
510 }
511 }
512
513 public function get($flags, $limit = null)
514 {
515 $res = array();
516 $nb = 0;
517 foreach ($this->addresses as $addr) {
518 if ($addr->hasFlags($flags)) {
519 $res[] = $addr;
520 $nb++;
521 }
522 if ($limit != null && $nb == $limit) {
523 break;
524 }
525 }
526 return PlIteratorUtils::fromArray($res);
527 }
528
529 public static function fetchData(array $pids, $visibility)
530 {
531 $data = XDB::iterator('SELECT pid, text, postalCode, type, latitude, longitude,
532 flags, type
533 FROM profile_addresses
534 WHERE pid in {?} AND pub IN {?}
535 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
536 $pids, $visibility);
537
538 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
539 }
540
541 public function addPhones($phones)
542 {
543 foreach ($phones as $phone) {
544 if ($phone->link_type == Phone::LINK_ADDRESS && array_key_exists($phone->link_id, $this->addresses)) {
545 $this->addresses[$phone->link_id]->addPhone($phone);
546 }
547 }
548 }
549 }
550 // }}}
551 // {{{ class ProfilePhones [ Field ]
552 class ProfilePhones extends ProfileField
553 {
554 private $phones = array();
555
556 public function __construct(PlIterator $phones)
557 {
558 while ($phone = $it->next()) {
559 $this->phones[] = Phone::buildFromData($phone);
560 }
561 }
562
563 public static function fetchData(array $pids, $visibility)
564 {
565 $data = XDB::iterator('SELECT type, search, display, link_type, comment
566 FROM profile_phones
567 WHERE pid IN {?} AND pub IN {?}
568 ORDER BY ' . XDB::formatCustomOrder('pid', $pids),
569 XDB::formatArray($pids),
570 XDB::formatArray($visibility)
571 );
572 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
573 }
574 }
575 // }}}
576 // {{{ class ProfileJobs [ Field ]
577 class ProfileJobs extends ProfileField
578 {
579 private $jobs = array();
580
581 public function __construct(PlIterator $jobs)
582 {
583 while ($job = $jobs->next()) {
584 $this->jobs[$job['id']] = new Job($job);
585 }
586 }
587
588 public static function fetchData(array $pids, $visibility)
589 {
590 $data = XDB::iterator('SELECT id, pid, description, url,
591 jobid, sectorid, subsectorid, subsubsectorid,
592 IF(email_pub IN {?}, email, NULL) AS email
593 FROM profile_job
594 WHERE pid IN {?} AND pub IN {?}
595 ORDER BY ' . XDB::formatCustomOrder('pid', $pids) . ',
596 id',
597 $visibility, $pids, $visibility);
598 return PlIteratorUtils::subIterator($data, PlIteratorUtils::arrayValueCallback('pid'));
599 }
600
601 public function get($flags, $limit = null)
602 {
603 $jobs = array();
604 $nb = 0;
605 foreach ($this->jobs as $id => $job) {
606 $jobs[$id] = $job;
607 ++$nb;
608 if ($limit != null && $nb >= $limit) {
609 break;
610 }
611 }
612 return PlIteratorUtils::fromArray($jobs);
613 }
614
615 public function addPhones(array $phones)
616 {
617 foreach ($phones as $phone)
618 {
619 if ($phone->link_type == Phone::LINK_JOB && array_key_exists($phone->link_id, $this->jobs)) {
620 $this->jobs[$phone->link_id]->addPhones($phone);
621 }
622 }
623 }
624
625 public static function addAddresses(array $addresses)
626 {
627 foreach ($addresses as $address)
628 {
629 if ($address->link_type == Address::LINK_JOB && array_key_exists($address->link_id, $this->jobs)) {
630 $this->jobs[$address->link_id]->setAddress($address);
631 }
632 }
633 }
634
635 public static function addCompanies(array $companies)
636 {
637 foreach ($this->jobs as $job)
638 {
639 $job->setCompany($companies[$job->company_id]);
640 }
641 }
642 }
643 // }}}
644
645 // {{{ class CompanyList
646 class CompanyList
647 {
648 static private $fullload = false;
649 static private $companies = array();
650
651 static public function preload($pids = array())
652 {
653 if (self::$fullload) {
654 return;
655 }
656 // Load raw data
657 if (count($pids)) {
658 $join = 'LEFT JOIN profile_jobs ON (profile_job.jobid = profile_job_enum.id)';
659 $where = 'profile_jobs.pid IN ' . XDB::formatArray($pids);
660 } else {
661 $join = '';
662 $where = '';
663 }
664
665 $it = XDB::iterator('SELECT pje.id, pje.name, pje.acronmy, pje.url,
666 pa.flags, pa.text, pa.postcode, pa.country,
667 pa.link_type, pa.pub
668 FROM profile_job_enum AS pje
669 LEFT JOIN profile_addresses AS pa ON (pje.id = pa.jobid AND pa.type = \'hq\')
670 ' . $join . '
671 ' . $where);
672 while ($row = $it->next()) {
673 $cp = Company::buildFromData($row);
674 $addr = Address::buildFromData($row);
675 $cp->setAddress($addr);
676 self::$companies[$row['id']] = $cp;
677 }
678
679 // TODO: add phones to addresses
680 if (count($pids) == 0) {
681 self::$fullload = true;
682 }
683 }
684
685 static public function getCompany($id)
686 {
687 if (!array_key_exists($id, self::$companies)) {
688 self::preload();
689 }
690 return self::$companies[$id];
691 }
692 }
693
694 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
695 ?>