0) { foreach ($data as $key => $val) { $this->$key = $val; } } if (!is_null($this->flags)) { $this->flags = new PlFlagSet($this->flags); } else { static $flags = array('current', 'temporary', 'secondary', 'mail', 'deliveryIssue'); $this->flags = new PlFlagSet(); foreach ($flags as $flag) { if (!is_null($this->$flag) && ($this->$flag == 1 || $this->$flag == 'on')) { $this->flags->addFlag($flag, 1); $this->$flag = null; } $this->flags->addFlag('cedex', (strpos(strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"), array('', "\n"), $this->text)), 'CEDEX')) !== false); } } } public function setId($id) { $this->id = $id; } public function phones() { return $this->phones; } public function addPhone(Phone &$phone) { if ($phone->linkType() == Phone::LINK_ADDRESS && $phone->pid() == $this->pid) { $this->phones[$phone->uniqueId()] = $phone; } } public function hasFlag($flag) { return ($this->flags != null && $this->flags->hasFlag($flag)); } // Returns the address formated for postal use. // The main rules are (cf AFNOR XPZ 10-011): // -everything in upper case; // -if there are more then than 38 characters in a line, split it; // -if there are more then than 32 characters in the description of the "street", use abbreviations. public function formatPostalAddress() { static $abbreviations = array( 'IMPASSE' => 'IMP', 'RUE' => 'R', 'AVENUE' => 'AV', 'BOULEVARD' => 'BVD', 'ROUTE' => 'R', 'STREET' => 'ST', 'ROAD' => 'RD', ); $text = strtoupper($text); $arrayText = explode("\n", $text); $postalText = ''; foreach ($arrayText as $i => $line) { $postalText .= (($i == 0) ? '' : "\n"); if (($length = strlen($line)) > 32) { $words = explode(' ', $line); $count = 0; foreach ($words as $word) { if (isset($abbreviations[$word])) { $word = $abbreviations[$word]; } if ($count + ($wordLength = strlen($word)) <= 38) { $postalText .= (($count == 0) ? '' : ' ') . $word; $count += (($count == 0) ? 0 : 1) + $wordLength; } else { $postalText .= "\n" . $word; $count = strlen($word); } } } else { $postalText .= $line; } } $this->postalText = $postalText; } public function format(array $format = array()) { if (empty($format)) { $format['requireGeocoding'] = false; $format['stripGeocoding'] = false; $format['postalText'] = false; } $this->text = trim($this->text); if ($this->removed == 1) { $this->text = ''; return true; } if ($format['requireGeocoding'] || $this->changed == 1) { $gmapsGeocoder = new GMapsGeocoder(); $gmapsGeocoder->getGeocodedAddress($this); $this->changed = 0; $this->error = !empty($this->geocodedText); } if ($format['stripGeocoding'] || ($this->type == self::LINK_COMPANY && $this->error) || $this->geocodeChosen === '0') { $gmapsGeocoder = new GMapsGeocoder(); $gmapsGeocoder->stripGeocodingFromAddress($this); if ($this->geocodeChosen === '0') { $mailer = new PlMailer('profile/geocoding.mail.tpl'); $mailer->assign('text', $this->text); $mailer->assign('geoloc', $this->geocodedText); $mailer->send(); } } if ($format['postalText']) { $this->formatPostalAddress(); } if ($this->countryId == '') { $this->countryId = null; } $this->geocodeChosen = null; $this->phones = Phone::formatFormArray($this->phones, $this->error); return !$this->error; } public function toFormArray() { $address = array( 'accuracy' => $this->accuracy, 'text' => $this->text, 'postalText' => $this->postalText, 'postalCode' => $this->postalCode, 'localityId' => $this->localityId, 'subAdministrativeAreaId' => $this->subAdministrativeAreaId, 'administrativeAreaId' => $this->administrativeAreaId, 'countryId' => $this->countryId, 'localityName' => $this->localityName, 'subAdministrativeAreaName' => $this->subAdministrativeAreaName, 'administrativeAreaName' => $this->administrativeAreaName, 'latitude' => $this->latitude, 'longitude' => $this->longitude, 'north' => $this->north, 'south' => $this->south, 'east' => $this->east, 'west' => $this->west, 'error' => $this->error, 'changed' => $this->changed, 'removed' => $this->removed, ); if (!is_null($this->geocodedText)) { $address['geocodedText'] = $this->geocodedText; $address['geocodeChosen'] = $this->geocodeChosen; } if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) { $address['pub'] = $this->pub; } if ($this->type == self::LINK_PROFILE) { static $flags = array('current', 'temporary', 'secondary', 'mail', 'cedex', 'deliveryIssue'); foreach ($flags as $flag) { $address[$flag] = $this->flags->hasFlag($flag); } $address['comment'] = $this->comment; $address['phones'] = Phone::formatFormArray($this->phones); } return $address; } private function toString() { $address = 'Adresse : ' . $this->text; if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) { $address .= ', affichage : ' . $this->pub; } if ($this->type == self::LINK_PROFILE) { static $flags = array( 'current' => 'actuelle', 'temporary' => 'temporaire', 'secondary' => 'secondaire', 'mail' => 'conctactable par courier', 'deliveryIssue' => 'n\'habite pas à l\'adresse indiquée', 'cedex' => 'type cédex', ); $address .= ', commentaire : ' . $this->comment; foreach ($flags as $flag => $flagName) { if ($this->flags->hasFlag($flag)) { $address .= ', ' . $flagName; } } if ($phones = Phone::formArrayToString($this->phones)) { $address .= ', ' . $phones; } } return $address; } private function isEmpty() { return (!$this->text || $this->text == ''); } public function save() { static $areas = array('administrativeArea', 'subAdministrativeArea', 'locality'); $this->format(array('postalText')); if (!$this->isEmpty()) { foreach ($areas as $area) { Geocoder::getAreaId($this, $area); } XDB::execute('INSERT INTO profile_addresses (pid, jobid, type, id, flags, accuracy, text, postalText, postalCode, localityId, subAdministrativeAreaId, administrativeAreaId, countryId, latitude, longitude, pub, comment, north, south, east, west) VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})', $this->pid, $this->jobid, $this->type, $this->id, $this->flags, $this->accuracy, $this->text, $this->postalText, $this->postalCode, $this->localityId, $this->subAdministrativeAreaId, $this->administrativeAreaId, $this->countryId, $this->latitude, $this->longitude, $this->pub, $this->comment, $this->north, $this->south, $this->east, $this->west); if ($this->type == self::LINK_PROFILE) { Phone::savePhones($this->phones, $this->pid, Phone::LINK_ADDRESS, $this->id); } } } public function delete() { XDB::execute('DELETE FROM profile_addresses WHERE pid = {?} AND jobid = {?} AND type = {?} AND id = {?}', $this->pid, $this->jobid, $this->type, $this->id); } static public function deleteAddresses($pid, $type, $jobid = null) { $where = ''; if (!is_null($pid)) { $where = XDB::format(' AND pid = {?}', $pid); } if (!is_null($jobid)) { $where = XDB::format(' AND jobid = {?}', $jobid); } XDB::execute('DELETE FROM profile_addresses WHERE type = {?}' . $where, $type); if ($type == self::LINK_PROFILE) { Phone::deletePhones($pid, Phone::LINK_ADDRESS); } } /** Saves addresses into the database. * @param $data: an array of form formatted addresses. * @param $pid, $type, $linkid: pid, type and id concerned by the update. */ static public function saveFromArray(array $data, $pid, $type = self::LINK_PROFILE, $linkid = null) { foreach ($data as $id => $value) { if (!is_null($linkid)) { $value['id'] = $linkid; } else { $value['id'] = $id; } if (!is_null($pid)) { $value['pid'] = $pid; } if (!is_null($type)) { $value['type'] = $type; } $address = new Address($value); $address->save(); } } static private function formArrayWalk(array $data, $function, &$success = true, $requiresEmptyAddress = false) { $addresses = array(); foreach ($data as $item) { $address = new Address($item); $success = ($address->format() && $success); if (!$address->isEmpty()) { $addresses[] = call_user_func(array($address, $function)); } } if (count($address) == 0 && $requiresEmptyAddress) { $address = new Address(); $addresses[] = call_user_func(array($address, $function)); } return $addresses; } // Formats an array of form addresses into an array of form formatted addresses. static public function formatFormArray(array $data, &$success = true) { // Only a single address can be the profile's current address and she must have one. $hasCurrent = false; foreach ($data as $key => &$address) { if (isset($address['current']) && $address['current']) { if ($hasCurrent) { $address['current'] = false; } else { $hasCurrent = true; } } } if (!$hasCurrent && count($value) > 0) { foreach ($value as &$address) { $address['current'] = true; break; } } return self::formArrayWalk($data, 'toFormArray', $success, true); } static public function formArrayToString(array $data) { return implode(' ; ', self::formArrayWalk($data, 'toString')); } static public function iterate(array $pids = array(), array $types = array(), array $jobids = array(), array $pubs = array()) { return new AddressIterator($pids, $types, $jobids, $pubs); } } /** Iterator over a set of Phones * * @param $pid, $type, $jobid, $pub * * The iterator contains the phones that correspond to the value stored in the * parameters' arrays. */ class AddressIterator implements PlIterator { private $dbiter; public function __construct(array $pids, array $types, array $jobids, array $pubs) { $where = array(); if (count($pids) != 0) { $where[] = XDB::format('(pa.pid IN {?})', $pids); } if (count($types) != 0) { $where[] = XDB::format('(pa.type IN {?})', $types); } if (count($jobids) != 0) { $where[] = XDB::format('(pa.jobid IN {?})', $jobids); } if (count($pubs) != 0) { $where[] = XDB::format('(pa.pub IN {?})', $pubs); } $sql = 'SELECT pa.pid, pa.jobid, pa.type, pa.id, pa.flags, pa.accuracy, pa.text, pa.postalText, pa.postalCode, pa.localityId, pa.subAdministrativeAreaId, pa.administrativeAreaId, pa.countryId, pa.latitude, pa.longitude, pa.north, pa.south, pa.east, pa.west, pa.pub, pa.comment, gl.name AS locality, gs.name AS subAdministrativeArea, ga.name AS administrativeArea, gc.countryFR AS country FROM profile_addresses AS pa LEFT JOIN geoloc_localities AS gl ON (gl.id = pa.localityId) LEFT JOIN geoloc_administrativeareas AS ga ON (ga.id = pa.administrativeAreaId) LEFT JOIN geoloc_subadministrativeareas AS gs ON (gs.id = pa.subAdministrativeAreaId) LEFT JOIN geoloc_countries AS gc ON (gc.iso_3166_1_a2 = pa.countryId) ' . ((count($where) > 0) ? 'WHERE ' . implode(' AND ', $where) : '') . ' ORDER BY pa.pid, pa.jobid, pa.id'; $this->dbiter = XDB::iterator($sql); } public function next() { if (is_null($this->dbiter)) { return null; } $data = $this->dbiter->next(); if (is_null($data)) { return null; } // Adds phones to addresses. $it = Phone::iterate(array($data['pid']), array(Phone::LINK_ADDRESS), array($data['id'])); while ($phone = $it->next()) { $data['phones'][$phone->id()] = $phone->toFormArray(); } return new Address($data); } public function total() { return $this->dbiter->total(); } public function first() { return $this->dbiter->first(); } public function last() { return $this->dbiter->last(); } public function value() { return $this->dbiter; } } // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: ?>