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