Commit | Line | Data |
---|---|---|
eb54852e SJ |
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 Address is meant to perform most of the access to the table profile_addresses. | |
23 | * | |
24 | * profile_addresses describes an Address, which can be related to either a | |
25 | * Profile, a Job or a Company: | |
26 | * - for a Profile: | |
27 | * - `type` is set to 'home' | |
28 | * - `pid` is set to the related profile pid (in profiles) | |
29 | * - `id` is the id of the address in the list of those related to that profile | |
30 | * - `jobid` is set to 0 | |
31 | * | |
32 | * - for a Company: | |
33 | * - `type` is set to 'hq' | |
34 | * - `pid` is set to 0 | |
35 | * - `jobid` is set to the id of the company (in profile_job_enum) | |
36 | * - `id` is set to 0 (only one address per Company) | |
37 | * | |
38 | * - for a Job: | |
39 | * - `type` is set to 'job' | |
40 | * - `pid` is set to the pid of the Profile of the related Job (in both profiles and profile_job) | |
41 | * - `id` is the id of the job to which we refer (in profile_job) | |
42 | * - `jobid` is set to 0 | |
43 | * | |
44 | * Thus an Address can be linked to a Company, a Profile, or a Job. | |
45 | */ | |
46 | class Address | |
47 | { | |
48 | const LINK_JOB = 'job'; | |
49 | const LINK_COMPANY = 'hq'; | |
50 | const LINK_PROFILE = 'home'; | |
51 | ||
52 | // Primary key fields: the quadruplet ($pid, $jobid, $type, $id) defines a unique address. | |
53 | public $pid = 0; | |
54 | public $jobid = 0; | |
55 | public $type = Address::LINK_PROFILE; | |
56 | public $id = 0; | |
57 | ||
58 | // Geocoding fields. | |
59 | public $accuracy = 0; | |
60 | public $text = ''; | |
61 | public $postalText = ''; | |
62 | public $postalCode = null; | |
63 | public $localityId = null; | |
64 | public $subAdministrativeAreaId = null; | |
65 | public $administrativeAreaId = null; | |
66 | public $localityName = null; | |
67 | public $subAdministrativeAreaName = null; | |
68 | public $administrativeAreaName = null; | |
69 | public $countryId = null; | |
70 | public $latitude = null; | |
71 | public $longitude = null; | |
72 | public $north = null; | |
73 | public $south = null; | |
74 | public $east = null; | |
75 | public $west = null; | |
76 | public $geocodedText = null; | |
77 | public $geocodedPostalText = null; | |
78 | public $geocodeChosen = null; | |
79 | ||
80 | // Database's field required for both 'home' and 'job' addresses. | |
81 | public $pub = 'private'; | |
82 | ||
83 | // Database's fields required for 'home' addresses. | |
84 | public $flags = null; // 'current', 'temporary', 'secondary', 'mail', 'cedex' | |
85 | public $comment = null; | |
86 | public $current = null; | |
87 | public $temporary = null; | |
88 | public $secondary = null; | |
89 | public $mail = null; | |
90 | ||
91 | // Remaining fields that do not belong to profile_addresses. | |
92 | public $phones = array(); | |
93 | public $error = false; | |
94 | public $changed = 0; | |
95 | public $removed = 0; | |
96 | ||
97 | public function __construct(array $data = array()) | |
98 | { | |
99 | if (count($data) > 0) { | |
100 | foreach ($data as $key => $val) { | |
101 | $this->$key = $val; | |
102 | } | |
103 | } | |
104 | ||
545bc699 FB |
105 | if (!is_null($this->flags)) { |
106 | $this->flags = new PlFlagSet($this->flags); | |
107 | } else { | |
108 | static $flags = array('current', 'temporary', 'secondary', 'mail'); | |
eb54852e | 109 | |
545bc699 FB |
110 | $this->flags = new PlFlagSet(); |
111 | foreach ($flags as $flag) { | |
112 | if (!is_null($this->$flag) && ($this->$flag == 1 || $this->$flag == 'on')) { | |
113 | $this->flags->addFlag($flag, 1); | |
114 | $this->$flag = null; | |
eb54852e | 115 | } |
545bc699 FB |
116 | $this->flags->addFlag('cedex', (strpos(strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"), |
117 | array('', "\n"), $this->text)), 'CEDEX')) !== false); | |
eb54852e SJ |
118 | } |
119 | } | |
120 | } | |
121 | ||
323ac187 SJ |
122 | public function setId($id) |
123 | { | |
124 | $this->id = $id; | |
125 | } | |
126 | ||
eb54852e SJ |
127 | public function phones() |
128 | { | |
129 | return $this->phones; | |
130 | } | |
131 | ||
132 | public function addPhone(Phone &$phone) | |
133 | { | |
134 | if ($phone->linkType() == Phone::LINK_ADDRESS && $phone->pid() == $this->pid) { | |
135 | $this->phones[$phone->uniqueId()] = $phone; | |
136 | } | |
137 | } | |
138 | ||
139 | public function hasFlag($flag) | |
140 | { | |
622e7063 | 141 | return ($this->flags != null && $this->flags->hasFlag($flag)); |
eb54852e SJ |
142 | } |
143 | ||
144 | public function format(array $format = array()) | |
145 | { | |
146 | if (empty($format)) { | |
147 | $format['requireGeocoding'] = false; | |
148 | $format['stripGeocoding'] = false; | |
149 | } | |
150 | $this->text = trim($this->text); | |
151 | if ($this->removed == 1) { | |
152 | $this->text = ''; | |
153 | return true; | |
154 | } | |
155 | ||
eb54852e SJ |
156 | if ($format['requireGeocoding'] || $this->changed == 1) { |
157 | $gmapsGeocoder = new GMapsGeocoder(); | |
158 | $gmapsGeocoder->getGeocodedAddress($this); | |
159 | $this->changed = 0; | |
160 | $this->error = !empty($this->geocodedText); | |
161 | } | |
162 | if ($format['stripGeocoding'] || ($this->type == self::LINK_COMPANY && $this->error) || $this->geocodeChosen === '0') { | |
163 | $gmapsGeocoder = new GMapsGeocoder(); | |
164 | $gmapsGeocoder->stripGeocodingFromAddress($this); | |
165 | if ($this->geocodeChosen === '0') { | |
166 | $mailer = new PlMailer('profile/geocoding.mail.tpl'); | |
167 | $mailer->assign('text', $this->text); | |
168 | $mailer->assign('geoloc', $this->geocodedText); | |
169 | $mailer->send(); | |
170 | } | |
171 | } | |
f2ac8f49 SJ |
172 | if ($this->countryId == '') { |
173 | $this->countryId = null; | |
174 | } | |
eb54852e SJ |
175 | $this->geocodeChosen = null; |
176 | $this->phones = Phone::formatFormArray($this->phones, $this->error); | |
177 | return !$this->error; | |
178 | } | |
179 | ||
180 | public function toFormArray() | |
181 | { | |
182 | $address = array( | |
183 | 'accuracy' => $this->accuracy, | |
184 | 'text' => $this->text, | |
185 | 'postalText' => $this->postalText, | |
186 | 'postalCode' => $this->postalCode, | |
187 | 'localityId' => $this->localityId, | |
188 | 'subAdministrativeAreaId' => $this->subAdministrativeAreaId, | |
189 | 'administrativeAreaId' => $this->administrativeAreaId, | |
190 | 'countryId' => $this->countryId, | |
191 | 'localityName' => $this->localityName, | |
192 | 'subAdministrativeAreaName' => $this->subAdministrativeAreaName, | |
193 | 'administrativeAreaName' => $this->administrativeAreaName, | |
194 | 'latitude' => $this->latitude, | |
195 | 'longitude' => $this->longitude, | |
196 | 'north' => $this->north, | |
197 | 'south' => $this->south, | |
198 | 'east' => $this->east, | |
199 | 'west' => $this->west, | |
200 | 'error' => $this->error, | |
201 | 'changed' => $this->changed, | |
202 | 'removed' => $this->removed, | |
203 | ); | |
204 | if (!is_null($this->geocodedText)) { | |
205 | $address['geocodedText'] = $this->geocodedText; | |
206 | $address['geocodedPostalText'] = $this->geocodedPostalText; | |
207 | $address['geocodeChosen'] = $this->geocodeChosen; | |
208 | } | |
209 | ||
210 | if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) { | |
211 | $address['pub'] = $this->pub; | |
212 | } | |
213 | if ($this->type == self::LINK_PROFILE) { | |
214 | static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex'); | |
215 | ||
216 | foreach ($flags as $flag) { | |
217 | $address[$flag] = $this->flags->hasFlag($flag); | |
218 | } | |
219 | $address['comment'] = $this->comment; | |
220 | $address['phones'] = Phone::formatFormArray($this->phones); | |
221 | } | |
222 | ||
223 | return $address; | |
224 | } | |
225 | ||
226 | private function toString() | |
227 | { | |
228 | $address = 'Adresse : ' . $this->text; | |
229 | if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) { | |
230 | $address .= ', affichage : ' . $this->pub; | |
231 | } | |
232 | if ($this->type == self::LINK_PROFILE) { | |
233 | static $flags = array( | |
234 | 'current' => 'actuelle', | |
235 | 'temporary' => 'temporaire', | |
236 | 'secondary' => 'secondaire', | |
237 | 'mail' => 'conctactable par courier', | |
238 | 'cedex' => 'type cédex', | |
239 | ); | |
240 | ||
241 | $address .= ', commentaire : ' . $this->comment; | |
242 | foreach ($flags as $flag => $flagName) { | |
243 | if ($this->flags->hasFlag($flag)) { | |
244 | $address .= ', ' . $flagName; | |
245 | } | |
246 | } | |
247 | if ($phones = Phone::formArrayToString($this->phones)) { | |
248 | $address .= ', ' . $phones; | |
249 | } | |
250 | } | |
251 | return $address; | |
252 | } | |
253 | ||
254 | private function isEmpty() | |
255 | { | |
256 | return (!$this->text || $this->text == ''); | |
257 | } | |
258 | ||
259 | public function save() | |
260 | { | |
261 | static $areas = array('administrativeArea', 'subAdministrativeArea', 'locality'); | |
262 | ||
263 | $this->format(); | |
264 | if (!$this->isEmpty()) { | |
eb54852e SJ |
265 | foreach ($areas as $area) { |
266 | Geocoder::getAreaId($this, $area); | |
267 | } | |
268 | ||
269 | XDB::execute('INSERT INTO profile_addresses (pid, jobid, type, id, flags, accuracy, | |
270 | text, postalText, postalCode, localityId, | |
271 | subAdministrativeAreaId, administrativeAreaId, | |
51d30e26 | 272 | countryId, latitude, longitude, pub, comment, |
eb54852e | 273 | north, south, east, west) |
51d30e26 SJ |
274 | VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, |
275 | {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})', | |
eb54852e SJ |
276 | $this->pid, $this->jobid, $this->type, $this->id, $this->flags, $this->accuracy, |
277 | $this->text, $this->postalText, $this->postalCode, $this->localityId, | |
278 | $this->subAdministrativeAreaId, $this->administrativeAreaId, | |
279 | $this->countryId, $this->latitude, $this->longitude, | |
51d30e26 | 280 | $this->pub, $this->comment, |
eb54852e SJ |
281 | $this->north, $this->south, $this->east, $this->west); |
282 | ||
283 | if ($this->type == self::LINK_PROFILE) { | |
284 | Phone::savePhones($this->phones, $this->pid, Phone::LINK_ADDRESS, $this->id); | |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | static public function delete($pid, $type, $jobid = null) | |
290 | { | |
291 | $where = ''; | |
292 | if (!is_null($pid)) { | |
293 | $where = XDB::format(' AND pid = {?}', $pid); | |
294 | } | |
295 | if (!is_null($jobid)) { | |
296 | $where = XDB::format(' AND jobid = {?}', $jobid); | |
297 | } | |
298 | XDB::execute('DELETE FROM profile_addresses | |
299 | WHERE type = {?}' . $where, | |
300 | $type); | |
301 | if ($type == self::LINK_PROFILE) { | |
302 | Phone::deletePhones($pid, Phone::LINK_ADDRESS); | |
303 | } | |
304 | } | |
305 | ||
306 | /** Saves addresses into the database. | |
307 | * @param $data: an array of form formatted addresses. | |
308 | * @param $pid, $type, $linkid: pid, type and id concerned by the update. | |
309 | */ | |
310 | static public function saveFromArray(array $data, $pid, $type = self::LINK_PROFILE, $linkid = null) | |
311 | { | |
312 | foreach ($data as $id => $value) { | |
313 | if (!is_null($linkid)) { | |
314 | $value['id'] = $linkid; | |
315 | } else { | |
316 | $value['id'] = $id; | |
317 | } | |
318 | if (!is_null($pid)) { | |
319 | $value['pid'] = $pid; | |
320 | } | |
321 | if (!is_null($type)) { | |
322 | $value['type'] = $type; | |
323 | } | |
324 | $address = new Address($value); | |
325 | $address->save(); | |
326 | } | |
327 | } | |
328 | ||
329 | static private function formArrayWalk(array $data, $function, &$success = true, $requiresEmptyAddress = false) | |
330 | { | |
331 | $addresses = array(); | |
332 | foreach ($data as $item) { | |
333 | $address = new Address($item); | |
334 | $success = ($address->format() && $success); | |
335 | if (!$address->isEmpty()) { | |
336 | $addresses[] = call_user_func(array($address, $function)); | |
337 | } | |
338 | } | |
339 | if (count($address) == 0 && $requiresEmptyAddress) { | |
340 | $address = new Address(); | |
341 | $addresses[] = call_user_func(array($address, $function)); | |
342 | } | |
343 | return $addresses; | |
344 | } | |
345 | ||
346 | // Formats an array of form addresses into an array of form formatted addresses. | |
347 | static public function formatFormArray(array $data, &$success = true) | |
348 | { | |
349 | // Only a single address can be the profile's current address and she must have one. | |
350 | $hasCurrent = false; | |
351 | foreach ($data as $key => &$address) { | |
352 | if (isset($address['current']) && $address['current']) { | |
353 | if ($hasCurrent) { | |
354 | $address['current'] = false; | |
355 | } else { | |
356 | $hasCurrent = true; | |
357 | } | |
358 | } | |
359 | } | |
360 | if (!$hasCurrent && count($value) > 0) { | |
361 | foreach ($value as &$address) { | |
362 | $address['current'] = true; | |
363 | break; | |
364 | } | |
365 | } | |
366 | ||
367 | return self::formArrayWalk($data, 'toFormArray', $success, true); | |
368 | } | |
369 | ||
370 | static public function formArrayToString(array $data) | |
371 | { | |
372 | return implode(' ; ', self::formArrayWalk($data, 'toString')); | |
373 | } | |
374 | ||
375 | static public function iterate(array $pids = array(), array $types = array(), | |
376 | array $jobids = array(), array $pubs = array()) | |
377 | { | |
378 | return new AddressIterator($pids, $types, $jobids, $pubs); | |
379 | } | |
380 | } | |
381 | ||
382 | /** Iterator over a set of Phones | |
383 | * | |
384 | * @param $pid, $type, $jobid, $pub | |
385 | * | |
386 | * The iterator contains the phones that correspond to the value stored in the | |
387 | * parameters' arrays. | |
388 | */ | |
389 | class AddressIterator implements PlIterator | |
390 | { | |
391 | private $dbiter; | |
392 | ||
393 | public function __construct(array $pids, array $types, array $jobids, array $pubs) | |
394 | { | |
395 | $where = array(); | |
396 | if (count($pids) != 0) { | |
397 | $where[] = XDB::format('(pa.pid IN {?})', $pids); | |
398 | } | |
399 | if (count($types) != 0) { | |
400 | $where[] = XDB::format('(pa.type IN {?})', $types); | |
401 | } | |
402 | if (count($jobids) != 0) { | |
403 | $where[] = XDB::format('(pa.jobid IN {?})', $jobids); | |
404 | } | |
405 | if (count($pubs) != 0) { | |
406 | $where[] = XDB::format('(pa.pub IN {?})', $pubs); | |
407 | } | |
408 | $sql = 'SELECT pa.pid, pa.jobid, pa.type, pa.id, pa.flags, | |
409 | pa.accuracy, pa.text, pa.postalText, pa.postalCode, | |
410 | pa.localityId, pa.subAdministrativeAreaId, | |
411 | pa.administrativeAreaId, pa.countryId, | |
412 | pa.latitude, pa.longitude, pa.north, pa.south, pa.east, pa.west, | |
413 | pa.pub, pa.comment, | |
414 | gl.name AS locality, gs.name AS subAdministrativeArea, | |
415 | ga.name AS administrativeArea, gc.countryFR AS country | |
416 | FROM profile_addresses AS pa | |
417 | LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId) | |
418 | LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId) | |
419 | LEFT JOIN geoloc_subadministrativeareas AS gs ON (gs.id = pa.subAdministrativeAreaId) | |
420 | LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId) | |
323ac187 | 421 | ' . ((count($where) > 0) ? 'WHERE ' . implode(' AND ', $where) : '') . ' |
eb54852e SJ |
422 | ORDER BY pa.pid, pa.jobid, pa.id'; |
423 | $this->dbiter = XDB::iterator($sql); | |
424 | } | |
425 | ||
426 | public function next() | |
427 | { | |
428 | if (is_null($this->dbiter)) { | |
429 | return null; | |
430 | } | |
431 | $data = $this->dbiter->next(); | |
432 | if (is_null($data)) { | |
433 | return null; | |
434 | } | |
435 | // Adds phones to addresses. | |
436 | $it = Phone::iterate(array($data['pid']), array(Phone::LINK_ADDRESS), array($data['id'])); | |
437 | while ($phone = $it->next()) { | |
438 | $data['phones'][$phone->id()] = $phone->toFormArray(); | |
439 | } | |
440 | return new Address($data); | |
441 | } | |
442 | ||
443 | public function total() | |
444 | { | |
445 | return $this->dbiter->total(); | |
446 | } | |
447 | ||
448 | public function first() | |
449 | { | |
450 | return $this->dbiter->first(); | |
451 | } | |
452 | ||
453 | public function last() | |
454 | { | |
455 | return $this->dbiter->last(); | |
456 | } | |
457 | ||
458 | public function value() | |
459 | { | |
460 | return $this->dbiter; | |
461 | } | |
462 | } | |
463 | ||
464 | // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: | |
465 | ?> |