Removes var_dump.
[platal.git] / classes / address.php
CommitLineData
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 */
46class 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
105 if ($this->type == self::LINK_PROFILE) {
106 if (!is_null($this->flags)) {
107 $this->flags = new PlFlagSet($this->flags);
108 } else {
109 static $flags = array('current', 'temporary', 'secondary', 'mail');
110
111 $this->flags = new PlFlagSet();
112 foreach ($flags as $flag) {
113 if (!is_null($this->$flag) && ($this->$flag == 1 || $this->$flag == 'on')) {
114 $this->flags->addFlag($flag, 1);
115 $this->$flag = null;
116 }
117 $this->flags->addFlag('cedex', (strpos(strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"),
118 array('', "\n"), $this->text)), 'CEDEX')) !== false);
119 }
120 }
121 }
122 }
123
124 public function phones()
125 {
126 return $this->phones;
127 }
128
129 public function addPhone(Phone &$phone)
130 {
131 if ($phone->linkType() == Phone::LINK_ADDRESS && $phone->pid() == $this->pid) {
132 $this->phones[$phone->uniqueId()] = $phone;
133 }
134 }
135
136 public function hasFlag($flag)
137 {
138 return $this->flags->hasFlag($flag);
139 }
140
141 public function format(array $format = array())
142 {
143 if (empty($format)) {
144 $format['requireGeocoding'] = false;
145 $format['stripGeocoding'] = false;
146 }
147 $this->text = trim($this->text);
148 if ($this->removed == 1) {
149 $this->text = '';
150 return true;
151 }
152
153 require_once 'geocoding.inc.php';
154 if ($format['requireGeocoding'] || $this->changed == 1) {
155 $gmapsGeocoder = new GMapsGeocoder();
156 $gmapsGeocoder->getGeocodedAddress($this);
157 $this->changed = 0;
158 $this->error = !empty($this->geocodedText);
159 }
160 if ($format['stripGeocoding'] || ($this->type == self::LINK_COMPANY && $this->error) || $this->geocodeChosen === '0') {
161 $gmapsGeocoder = new GMapsGeocoder();
162 $gmapsGeocoder->stripGeocodingFromAddress($this);
163 if ($this->geocodeChosen === '0') {
164 $mailer = new PlMailer('profile/geocoding.mail.tpl');
165 $mailer->assign('text', $this->text);
166 $mailer->assign('geoloc', $this->geocodedText);
167 $mailer->send();
168 }
169 }
170 $this->geocodeChosen = null;
171 $this->phones = Phone::formatFormArray($this->phones, $this->error);
172 return !$this->error;
173 }
174
175 public function toFormArray()
176 {
177 $address = array(
178 'accuracy' => $this->accuracy,
179 'text' => $this->text,
180 'postalText' => $this->postalText,
181 'postalCode' => $this->postalCode,
182 'localityId' => $this->localityId,
183 'subAdministrativeAreaId' => $this->subAdministrativeAreaId,
184 'administrativeAreaId' => $this->administrativeAreaId,
185 'countryId' => $this->countryId,
186 'localityName' => $this->localityName,
187 'subAdministrativeAreaName' => $this->subAdministrativeAreaName,
188 'administrativeAreaName' => $this->administrativeAreaName,
189 'latitude' => $this->latitude,
190 'longitude' => $this->longitude,
191 'north' => $this->north,
192 'south' => $this->south,
193 'east' => $this->east,
194 'west' => $this->west,
195 'error' => $this->error,
196 'changed' => $this->changed,
197 'removed' => $this->removed,
198 );
199 if (!is_null($this->geocodedText)) {
200 $address['geocodedText'] = $this->geocodedText;
201 $address['geocodedPostalText'] = $this->geocodedPostalText;
202 $address['geocodeChosen'] = $this->geocodeChosen;
203 }
204
205 if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) {
206 $address['pub'] = $this->pub;
207 }
208 if ($this->type == self::LINK_PROFILE) {
209 static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex');
210
211 foreach ($flags as $flag) {
212 $address[$flag] = $this->flags->hasFlag($flag);
213 }
214 $address['comment'] = $this->comment;
215 $address['phones'] = Phone::formatFormArray($this->phones);
216 }
217
218 return $address;
219 }
220
221 private function toString()
222 {
223 $address = 'Adresse : ' . $this->text;
224 if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) {
225 $address .= ', affichage : ' . $this->pub;
226 }
227 if ($this->type == self::LINK_PROFILE) {
228 static $flags = array(
229 'current' => 'actuelle',
230 'temporary' => 'temporaire',
231 'secondary' => 'secondaire',
232 'mail' => 'conctactable par courier',
233 'cedex' => 'type cédex',
234 );
235
236 $address .= ', commentaire : ' . $this->comment;
237 foreach ($flags as $flag => $flagName) {
238 if ($this->flags->hasFlag($flag)) {
239 $address .= ', ' . $flagName;
240 }
241 }
242 if ($phones = Phone::formArrayToString($this->phones)) {
243 $address .= ', ' . $phones;
244 }
245 }
246 return $address;
247 }
248
249 private function isEmpty()
250 {
251 return (!$this->text || $this->text == '');
252 }
253
254 public function save()
255 {
256 static $areas = array('administrativeArea', 'subAdministrativeArea', 'locality');
257
258 $this->format();
259 if (!$this->isEmpty()) {
260 require_once 'geocoding.inc.php';
261 foreach ($areas as $area) {
262 Geocoder::getAreaId($this, $area);
263 }
264
265 XDB::execute('INSERT INTO profile_addresses (pid, jobid, type, id, flags, accuracy,
266 text, postalText, postalCode, localityId,
267 subAdministrativeAreaId, administrativeAreaId,
268 countryId, latitude, longitude, updateTime, pub, comment,
269 north, south, east, west)
270 VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?},
271 {?}, {?}, {?}, FROM_UNIXTIME({?}), {?}, {?}, {?}, {?}, {?}, {?})',
272 $this->pid, $this->jobid, $this->type, $this->id, $this->flags, $this->accuracy,
273 $this->text, $this->postalText, $this->postalCode, $this->localityId,
274 $this->subAdministrativeAreaId, $this->administrativeAreaId,
275 $this->countryId, $this->latitude, $this->longitude,
276 time(), $this->pub, $this->comment,
277 $this->north, $this->south, $this->east, $this->west);
278
279 if ($this->type == self::LINK_PROFILE) {
280 Phone::savePhones($this->phones, $this->pid, Phone::LINK_ADDRESS, $this->id);
281 }
282 }
283 }
284
285 static public function delete($pid, $type, $jobid = null)
286 {
287 $where = '';
288 if (!is_null($pid)) {
289 $where = XDB::format(' AND pid = {?}', $pid);
290 }
291 if (!is_null($jobid)) {
292 $where = XDB::format(' AND jobid = {?}', $jobid);
293 }
294 XDB::execute('DELETE FROM profile_addresses
295 WHERE type = {?}' . $where,
296 $type);
297 if ($type == self::LINK_PROFILE) {
298 Phone::deletePhones($pid, Phone::LINK_ADDRESS);
299 }
300 }
301
302 /** Saves addresses into the database.
303 * @param $data: an array of form formatted addresses.
304 * @param $pid, $type, $linkid: pid, type and id concerned by the update.
305 */
306 static public function saveFromArray(array $data, $pid, $type = self::LINK_PROFILE, $linkid = null)
307 {
308 foreach ($data as $id => $value) {
309 if (!is_null($linkid)) {
310 $value['id'] = $linkid;
311 } else {
312 $value['id'] = $id;
313 }
314 if (!is_null($pid)) {
315 $value['pid'] = $pid;
316 }
317 if (!is_null($type)) {
318 $value['type'] = $type;
319 }
320 $address = new Address($value);
321 $address->save();
322 }
323 }
324
325 static private function formArrayWalk(array $data, $function, &$success = true, $requiresEmptyAddress = false)
326 {
327 $addresses = array();
328 foreach ($data as $item) {
329 $address = new Address($item);
330 $success = ($address->format() && $success);
331 if (!$address->isEmpty()) {
332 $addresses[] = call_user_func(array($address, $function));
333 }
334 }
335 if (count($address) == 0 && $requiresEmptyAddress) {
336 $address = new Address();
337 $addresses[] = call_user_func(array($address, $function));
338 }
339 return $addresses;
340 }
341
342 // Formats an array of form addresses into an array of form formatted addresses.
343 static public function formatFormArray(array $data, &$success = true)
344 {
345 // Only a single address can be the profile's current address and she must have one.
346 $hasCurrent = false;
347 foreach ($data as $key => &$address) {
348 if (isset($address['current']) && $address['current']) {
349 if ($hasCurrent) {
350 $address['current'] = false;
351 } else {
352 $hasCurrent = true;
353 }
354 }
355 }
356 if (!$hasCurrent && count($value) > 0) {
357 foreach ($value as &$address) {
358 $address['current'] = true;
359 break;
360 }
361 }
362
363 return self::formArrayWalk($data, 'toFormArray', $success, true);
364 }
365
366 static public function formArrayToString(array $data)
367 {
368 return implode(' ; ', self::formArrayWalk($data, 'toString'));
369 }
370
371 static public function iterate(array $pids = array(), array $types = array(),
372 array $jobids = array(), array $pubs = array())
373 {
374 return new AddressIterator($pids, $types, $jobids, $pubs);
375 }
376}
377
378/** Iterator over a set of Phones
379 *
380 * @param $pid, $type, $jobid, $pub
381 *
382 * The iterator contains the phones that correspond to the value stored in the
383 * parameters' arrays.
384 */
385class AddressIterator implements PlIterator
386{
387 private $dbiter;
388
389 public function __construct(array $pids, array $types, array $jobids, array $pubs)
390 {
391 $where = array();
392 if (count($pids) != 0) {
393 $where[] = XDB::format('(pa.pid IN {?})', $pids);
394 }
395 if (count($types) != 0) {
396 $where[] = XDB::format('(pa.type IN {?})', $types);
397 }
398 if (count($jobids) != 0) {
399 $where[] = XDB::format('(pa.jobid IN {?})', $jobids);
400 }
401 if (count($pubs) != 0) {
402 $where[] = XDB::format('(pa.pub IN {?})', $pubs);
403 }
404 $sql = 'SELECT pa.pid, pa.jobid, pa.type, pa.id, pa.flags,
405 pa.accuracy, pa.text, pa.postalText, pa.postalCode,
406 pa.localityId, pa.subAdministrativeAreaId,
407 pa.administrativeAreaId, pa.countryId,
408 pa.latitude, pa.longitude, pa.north, pa.south, pa.east, pa.west,
409 pa.pub, pa.comment,
410 gl.name AS locality, gs.name AS subAdministrativeArea,
411 ga.name AS administrativeArea, gc.countryFR AS country
412 FROM profile_addresses AS pa
413 LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId)
414 LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId)
415 LEFT JOIN geoloc_subadministrativeareas AS gs ON (gs.id = pa.subAdministrativeAreaId)
416 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId)
417 WHERE ' . implode(' AND ', $where) . '
418 ORDER BY pa.pid, pa.jobid, pa.id';
419 $this->dbiter = XDB::iterator($sql);
420 }
421
422 public function next()
423 {
424 if (is_null($this->dbiter)) {
425 return null;
426 }
427 $data = $this->dbiter->next();
428 if (is_null($data)) {
429 return null;
430 }
431 // Adds phones to addresses.
432 $it = Phone::iterate(array($data['pid']), array(Phone::LINK_ADDRESS), array($data['id']));
433 while ($phone = $it->next()) {
434 $data['phones'][$phone->id()] = $phone->toFormArray();
435 }
436 return new Address($data);
437 }
438
439 public function total()
440 {
441 return $this->dbiter->total();
442 }
443
444 public function first()
445 {
446 return $this->dbiter->first();
447 }
448
449 public function last()
450 {
451 return $this->dbiter->last();
452 }
453
454 public function value()
455 {
456 return $this->dbiter;
457 }
458}
459
460// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
461?>