2 /***************************************************************************
3 * Copyright (C) 2003-2010 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
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. *
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. *
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 *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
22 /** Class Address is meant to perform most of the access to the table profile_addresses.
24 * profile_addresses describes an Address, which can be related to either a
25 * Profile, a Job or a Company:
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
33 * - `type` is set to 'hq'
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)
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
44 * Thus an Address can be linked to a Company, a Profile, or a Job.
48 const LINK_JOB
= 'job';
49 const LINK_COMPANY
= 'hq';
50 const LINK_PROFILE
= 'home';
52 // Primary key fields: the quadruplet ($pid, $jobid, $type, $id) defines a unique address.
55 public $type = Address
::LINK_PROFILE
;
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
;
76 public $geocodedText = null
;
77 public $geocodedPostalText = null
;
78 public $geocodeChosen = null
;
80 // Database's field required for both 'home' and 'job' addresses.
81 public $pub = 'private';
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
;
91 // Remaining fields that do not belong to profile_addresses.
92 public $phones = array();
93 public $error = false
;
97 public function __construct(array $data = array())
99 if (count($data) > 0) {
100 foreach ($data as $key => $val) {
105 if ($this->type
== self
::LINK_PROFILE
) {
106 if (!is_null($this->flags
)) {
107 $this->flags
= new PlFlagSet($this->flags
);
109 static $flags = array('current', 'temporary', 'secondary', 'mail');
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);
117 $this->flags
->addFlag('cedex', (strpos(strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"),
118 array('', "\n"), $this->text
)), 'CEDEX')) !== false
);
124 public function phones()
126 return $this->phones
;
129 public function addPhone(Phone
&$phone)
131 if ($phone->linkType() == Phone
::LINK_ADDRESS
&& $phone->pid() == $this->pid
) {
132 $this->phones
[$phone->uniqueId()] = $phone;
136 public function hasFlag($flag)
138 return ($this->flags
!= null
&& $this->flags
->hasFlag($flag));
141 public function format(array $format = array())
143 if (empty($format)) {
144 $format['requireGeocoding'] = false
;
145 $format['stripGeocoding'] = false
;
147 $this->text
= trim($this->text
);
148 if ($this->removed
== 1) {
153 if ($format['requireGeocoding'] ||
$this->changed
== 1) {
154 $gmapsGeocoder = new GMapsGeocoder();
155 $gmapsGeocoder->getGeocodedAddress($this);
157 $this->error
= !empty($this->geocodedText
);
159 if ($format['stripGeocoding'] ||
($this->type
== self
::LINK_COMPANY
&& $this->error
) ||
$this->geocodeChosen
=== '0') {
160 $gmapsGeocoder = new GMapsGeocoder();
161 $gmapsGeocoder->stripGeocodingFromAddress($this);
162 if ($this->geocodeChosen
=== '0') {
163 $mailer = new PlMailer('profile/geocoding.mail.tpl');
164 $mailer->assign('text', $this->text
);
165 $mailer->assign('geoloc', $this->geocodedText
);
169 $this->geocodeChosen
= null
;
170 $this->phones
= Phone
::formatFormArray($this->phones
, $this->error
);
171 return !$this->error
;
174 public function toFormArray()
177 'accuracy' => $this->accuracy
,
178 'text' => $this->text
,
179 'postalText' => $this->postalText
,
180 'postalCode' => $this->postalCode
,
181 'localityId' => $this->localityId
,
182 'subAdministrativeAreaId' => $this->subAdministrativeAreaId
,
183 'administrativeAreaId' => $this->administrativeAreaId
,
184 'countryId' => $this->countryId
,
185 'localityName' => $this->localityName
,
186 'subAdministrativeAreaName' => $this->subAdministrativeAreaName
,
187 'administrativeAreaName' => $this->administrativeAreaName
,
188 'latitude' => $this->latitude
,
189 'longitude' => $this->longitude
,
190 'north' => $this->north
,
191 'south' => $this->south
,
192 'east' => $this->east
,
193 'west' => $this->west
,
194 'error' => $this->error
,
195 'changed' => $this->changed
,
196 'removed' => $this->removed
,
198 if (!is_null($this->geocodedText
)) {
199 $address['geocodedText'] = $this->geocodedText
;
200 $address['geocodedPostalText'] = $this->geocodedPostalText
;
201 $address['geocodeChosen'] = $this->geocodeChosen
;
204 if ($this->type
== self
::LINK_PROFILE ||
$this->type
== self
::LINK_JOB
) {
205 $address['pub'] = $this->pub
;
207 if ($this->type
== self
::LINK_PROFILE
) {
208 static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex');
210 foreach ($flags as $flag) {
211 $address[$flag] = $this->flags
->hasFlag($flag);
213 $address['comment'] = $this->comment
;
214 $address['phones'] = Phone
::formatFormArray($this->phones
);
220 private function toString()
222 $address = 'Adresse : ' . $this->text
;
223 if ($this->type
== self
::LINK_PROFILE ||
$this->type
== self
::LINK_JOB
) {
224 $address .= ', affichage : ' . $this->pub
;
226 if ($this->type
== self
::LINK_PROFILE
) {
227 static $flags = array(
228 'current' => 'actuelle',
229 'temporary' => 'temporaire',
230 'secondary' => 'secondaire',
231 'mail' => 'conctactable par courier',
232 'cedex' => 'type cédex',
235 $address .= ', commentaire : ' . $this->comment
;
236 foreach ($flags as $flag => $flagName) {
237 if ($this->flags
->hasFlag($flag)) {
238 $address .= ', ' . $flagName;
241 if ($phones = Phone
::formArrayToString($this->phones
)) {
242 $address .= ', ' . $phones;
248 private function isEmpty()
250 return (!$this->text ||
$this->text
== '');
253 public function save()
255 static $areas = array('administrativeArea', 'subAdministrativeArea', 'locality');
258 if (!$this->isEmpty()) {
259 foreach ($areas as $area) {
260 Geocoder
::getAreaId($this, $area);
263 XDB
::execute('INSERT INTO profile_addresses (pid, jobid, type, id, flags, accuracy,
264 text, postalText, postalCode, localityId,
265 subAdministrativeAreaId, administrativeAreaId,
266 countryId, latitude, longitude, pub, comment,
267 north, south, east, west)
268 VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?},
269 {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})',
270 $this->pid
, $this->jobid
, $this->type
, $this->id
, $this->flags
, $this->accuracy
,
271 $this->text
, $this->postalText
, $this->postalCode
, $this->localityId
,
272 $this->subAdministrativeAreaId
, $this->administrativeAreaId
,
273 $this->countryId
, $this->latitude
, $this->longitude
,
274 $this->pub
, $this->comment
,
275 $this->north
, $this->south
, $this->east
, $this->west
);
277 if ($this->type
== self
::LINK_PROFILE
) {
278 Phone
::savePhones($this->phones
, $this->pid
, Phone
::LINK_ADDRESS
, $this->id
);
283 static public function delete($pid, $type, $jobid = null
)
286 if (!is_null($pid)) {
287 $where = XDB
::format(' AND pid = {?}', $pid);
289 if (!is_null($jobid)) {
290 $where = XDB
::format(' AND jobid = {?}', $jobid);
292 XDB
::execute('DELETE FROM profile_addresses
293 WHERE type = {?}' . $where,
295 if ($type == self
::LINK_PROFILE
) {
296 Phone
::deletePhones($pid, Phone
::LINK_ADDRESS
);
300 /** Saves addresses into the database.
301 * @param $data: an array of form formatted addresses.
302 * @param $pid, $type, $linkid: pid, type and id concerned by the update.
304 static public function saveFromArray(array $data, $pid, $type = self
::LINK_PROFILE
, $linkid = null
)
306 foreach ($data as $id => $value) {
307 if (!is_null($linkid)) {
308 $value['id'] = $linkid;
312 if (!is_null($pid)) {
313 $value['pid'] = $pid;
315 if (!is_null($type)) {
316 $value['type'] = $type;
318 $address = new Address($value);
323 static private function formArrayWalk(array $data, $function, &$success = true
, $requiresEmptyAddress = false
)
325 $addresses = array();
326 foreach ($data as $item) {
327 $address = new Address($item);
328 $success = ($address->format() && $success);
329 if (!$address->isEmpty()) {
330 $addresses[] = call_user_func(array($address, $function));
333 if (count($address) == 0 && $requiresEmptyAddress) {
334 $address = new Address();
335 $addresses[] = call_user_func(array($address, $function));
340 // Formats an array of form addresses into an array of form formatted addresses.
341 static public function formatFormArray(array $data, &$success = true
)
343 // Only a single address can be the profile's current address and she must have one.
345 foreach ($data as $key => &$address) {
346 if (isset($address['current']) && $address['current']) {
348 $address['current'] = false
;
354 if (!$hasCurrent && count($value) > 0) {
355 foreach ($value as &$address) {
356 $address['current'] = true
;
361 return self
::formArrayWalk($data, 'toFormArray', $success, true
);
364 static public function formArrayToString(array $data)
366 return implode(' ; ', self
::formArrayWalk($data, 'toString'));
369 static public function iterate(array $pids = array(), array $types = array(),
370 array $jobids = array(), array $pubs = array())
372 return new AddressIterator($pids, $types, $jobids, $pubs);
376 /** Iterator over a set of Phones
378 * @param $pid, $type, $jobid, $pub
380 * The iterator contains the phones that correspond to the value stored in the
381 * parameters' arrays.
383 class AddressIterator
implements PlIterator
387 public function __construct(array $pids, array $types, array $jobids, array $pubs)
390 if (count($pids) != 0) {
391 $where[] = XDB
::format('(pa.pid IN {?})', $pids);
393 if (count($types) != 0) {
394 $where[] = XDB
::format('(pa.type IN {?})', $types);
396 if (count($jobids) != 0) {
397 $where[] = XDB
::format('(pa.jobid IN {?})', $jobids);
399 if (count($pubs) != 0) {
400 $where[] = XDB
::format('(pa.pub IN {?})', $pubs);
402 $sql = 'SELECT pa.pid, pa.jobid, pa.type, pa.id, pa.flags,
403 pa.accuracy, pa.text, pa.postalText, pa.postalCode,
404 pa.localityId, pa.subAdministrativeAreaId,
405 pa.administrativeAreaId, pa.countryId,
406 pa.latitude, pa.longitude, pa.north, pa.south, pa.east, pa.west,
408 gl.name AS locality, gs.name AS subAdministrativeArea,
409 ga.name AS administrativeArea, gc.countryFR AS country
410 FROM profile_addresses AS pa
411 LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId)
412 LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId)
413 LEFT JOIN geoloc_subadministrativeareas AS gs ON (gs.id = pa.subAdministrativeAreaId)
414 LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId)
415 WHERE ' . implode(' AND ', $where) . '
416 ORDER BY pa.pid, pa.jobid, pa.id';
417 $this->dbiter
= XDB
::iterator($sql);
420 public function next()
422 if (is_null($this->dbiter
)) {
425 $data = $this->dbiter
->next();
426 if (is_null($data)) {
429 // Adds phones to addresses.
430 $it = Phone
::iterate(array($data['pid']), array(Phone
::LINK_ADDRESS
), array($data['id']));
431 while ($phone = $it->next()) {
432 $data['phones'][$phone->id()] = $phone->toFormArray();
434 return new Address($data);
437 public function total()
439 return $this->dbiter
->total();
442 public function first()
444 return $this->dbiter
->first();
447 public function last()
449 return $this->dbiter
->last();
452 public function value()
454 return $this->dbiter
;
458 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: