From 0f5f1b707d93b4dc8c5875c2129bb38fcd186563 Mon Sep 17 00:00:00 2001 From: =?utf8?q?St=C3=A9phane=20Jacob?= Date: Fri, 6 May 2011 10:56:14 +0200 Subject: [PATCH] Changes geocoding engine to gmaps v3. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Jacob --- classes/address.php | 151 ++++++++++-------------- classes/geocoder.php | 80 +++---------- classes/gmapsgeocoder.php | 222 +++++++++-------------------------- configs/mails.conf | 2 +- configs/platal.ini | 14 +-- templates/geoloc/form.address.tpl | 21 ++-- templates/profile/geocoding.mail.tpl | 14 +-- upgrade/1.1.2/01_geocoding.sql | 59 ++++++++++ 8 files changed, 217 insertions(+), 346 deletions(-) create mode 100644 upgrade/1.1.2/01_geocoding.sql diff --git a/classes/address.php b/classes/address.php index fb4eb44..1b15158 100644 --- a/classes/address.php +++ b/classes/address.php @@ -296,26 +296,20 @@ class Address public $id = 0; // Geocoding fields. - public $accuracy = 0; public $text = ''; public $postalText = ''; - public $postalCode = null; - public $localityId = null; - public $subAdministrativeAreaId = null; - public $administrativeAreaId = null; - public $localityName = null; - public $subAdministrativeAreaName = null; - public $administrativeAreaName = null; - public $localityNameLocal = null; - public $subAdministrativeAreaNameLocal = null; - public $administrativeAreaNameLocal = null; - public $countryId = null; + public $types = ''; + public $formatted_address = ''; + public $components = array(); public $latitude = null; public $longitude = null; - public $north = null; - public $south = null; - public $east = null; - public $west = null; + public $southwest_latitude = null; + public $southwest_longitude = null; + public $northeast_latitude = null; + public $northeast_longitude = null; + public $location_type = ''; + public $partial_match = false; + public $componentsIds = ''; // Database's field required for both 'home' and 'job' addresses. public $pub = 'ax'; @@ -557,22 +551,18 @@ class Address // country, then apply corresponding formatting or translate country // into default language. $count = count($arrayText); - if (in_array(strtoupper($this->countryId), Address::$formattings)) { - $text = call_user_func(array($this, 'formatPostalAddress' . strtoupper($this->countryId)), $arrayText); + list($countryId, $country) = XDB::fetchOneRow('SELECT gc.iso_3166_1_a2, gc.country + FROM geoloc_countries AS gc + INNER JOIN geoloc_languages AS gl ON (gc.iso_3166_1_a2 = gl.iso_3166_1_a2) + WHERE gl.countryPlain = {?} OR gc.countryPlain = {?}', + $arrayText[$count - 1], $arrayText[$count - 1]); + if (is_null($countryId)) { + $text = $this->formatPostalAddressFR($arrayText); + } elseif (in_array(strtoupper($countryId), Address::$formattings)) { + $text = call_user_func(array($this, 'formatPostalAddress' . strtoupper($countryId)), $arrayText); } else { - list($countryId, $country) = XDB::fetchOneRow('SELECT gc.iso_3166_1_a2, gc.country - FROM geoloc_countries AS gc - INNER JOIN geoloc_languages AS gl ON (gc.iso_3166_1_a2 = gl.iso_3166_1_a2) - WHERE gc.iso_3166_1_a2 = {?} OR gl.countryPlain = {?} OR gc.countryPlain = {?}', - $this->countryId, $arrayText[$count - 1], $arrayText[$count - 1]); - if (is_null($countryId)) { - $text = $this->formatPostalAddressFR($arrayText); - } elseif (in_array(strtoupper($countryId), Address::$formattings)) { - $text = call_user_func(array($this, 'formatPostalAddress' . strtoupper($countryId)), $arrayText); - } else { - $arrayText[$count - 1] = mb_strtoupper(replace_accent($country)); - $text = implode("\n", $arrayText); - } + $arrayText[$count - 1] = mb_strtoupper(replace_accent($country)); + $text = implode("\n", $arrayText); } $this->postalText = $text; @@ -596,12 +586,12 @@ class Address $gmapsGeocoder = new GMapsGeocoder(); $gmapsGeocoder->getGeocodedAddress($this); } - foreach (array('administrativeArea', 'subAdministrativeArea', 'locality') as $area) { - Geocoder::getAreaId($this, $area); - } - if ($this->countryId == '') { - $this->countryId = null; + + $componants = array(); + foreach ($this->components as $component) { + $componants[] = Geocoder::getComponentId($component); } + $this->componentsIds = implode(',', $componants); return true; } @@ -609,29 +599,19 @@ class Address 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, - 'localityNameLocal' => $this->localityNameLocal, - 'subAdministrativeAreaNameLocal' => $this->subAdministrativeAreaNameLocal, - 'administrativeAreaNameLocal' => $this->administrativeAreaNameLocal, - '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, + 'text' => $this->text, + 'postalText' => $this->postalText, + 'types' => $this->types, + 'formatted_address' => $this->formatted_address, + 'latitude' => $this->latitude, + 'longitude' => $this->longitude, + 'southwest_latitude' => $this->southwest_latitude, + 'southwest_longitude' => $this->southwest_longitude, + 'northeast_latitude' => $this->northeast_latitude, + 'northeast_longitude' => $this->northeast_longitude, + 'location_type' => $this->location_type, + 'partial_match' => $this->partial_match, + 'componentsIds' => $this->componentsIds ); if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) { @@ -639,7 +619,6 @@ class Address } 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); } @@ -698,19 +677,22 @@ class Address public function save() { if (!$this->isEmpty()) { - XDB::execute('INSERT IGNORE INTO profile_addresses (pid, jobid, groupid, 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->groupid, $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); + XDB::execute('INSERT IGNORE INTO profile_addresses (pid, jobid, groupid, type, id, flags, text, postalText, pub, comment, + types, formatted_address, location_type, partial_match, latitude, longitude, + southwest_latitude, southwest_longitude, northeast_latitude, northeast_longitude) + VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, + {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})', + $this->pid, $this->jobid, $this->groupid, $this->type, $this->id, $this->flags, $this->text, $this->postalText, $this->pub, $this->comment, + $this->types, $this->formatted_address, $this->location_type, $this->partial_match, $this->latitude, $this->longitude, + $this->southwest_latitude, $this->southwest_longitude, $this->northeast_latitude, $this->northeast_longitude); + + if ($this->componentsIds) { + foreach (explode(',', $this->componentsIds) as $component_id) { + XDB::execute('INSERT IGNORE INTO profile_addresses_components (pid, jobid, groupid, type, id, component_id) + VALUES ({?}, {?}, {?}, {?}, {?}, {?})', + $this->pid, $this->jobid, $this->groupid, $this->type, $this->id, $component_id); + } + } if ($this->type == self::LINK_PROFILE) { Phone::savePhones($this->phones, $this->pid, Phone::LINK_ADDRESS, $this->id); @@ -875,22 +857,15 @@ class AddressIterator implements PlIterator 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, gl.nameLocal AS localityLocal, - gs.name AS subAdministrativeArea, gs.nameLocal AS subAdministrativeAreaLocal, - ga.name AS administrativeArea, ga.nameLocal AS administrativeAreaLocal, - gc.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) + $sql = 'SELECT pa.pid, pa.jobid, pa.groupid, pa.type, pa.id, pa.flags, pa.text, pa.postalText, pa.pub, pa.comment, + pa.types, pa.formatted_address, pa.location_type, pa.partial_match, pa.latitude, pa.longitude, + pa.southwest_latitude, pa.southwest_longitude, pa.northeast_latitude, pa.northeast_longitude, + GROUP_CONCAT(DISTINCT pc.component_id SEPARATOR \',\') AS componentsIds + FROM profile_addresses AS pa + LEFT JOIN profile_addresses_components AS pc ON (pa.pid = pc.pid AND pa.jobid = pc.jobid AND pa.groupid = pc.groupid + AND pa.type = pc.type AND pa.id = pc.id) ' . ((count($where) > 0) ? 'WHERE ' . implode(' AND ', $where) : '') . ' + GROUP BY pa.pid, pa.jobid, pa.groupid, pa.type, pa.id ORDER BY pa.pid, pa.jobid, pa.id'; $this->dbiter = XDB::iterator($sql); } diff --git a/classes/geocoder.php b/classes/geocoder.php index 825b920..f404304 100644 --- a/classes/geocoder.php +++ b/classes/geocoder.php @@ -29,54 +29,26 @@ abstract class Geocoder { // Cleans the address from its geocoded data abstract public function stripGeocodingFromAddress(Address $address); - // Updates geoloc_administrativeareas, geoloc_subadministrativeareas and - // geoloc_localities databases with new geocoded data and returns the - // corresponding id. - static public function getAreaId(Address $address, $area) + // Updates profile_addresses_components_enum, if needed, with new + // geocoded data and returns the corresponding id. + static public function getComponentId(array $component) { - static $databases = array( - 'administrativeArea' => 'geoloc_administrativeareas', - 'subAdministrativeArea' => 'geoloc_subadministrativeareas', - 'locality' => 'geoloc_localities', - ); - static $extras = array( - 'subAdministrativeArea' => array( - 'field' => 'administrativearea', - 'name' => 'administrativeAreaName' - ) - ); - - $areaName = $area . 'Name'; - $areaNameLocal = $areaName . 'Local'; - $areaId = $area . 'Id'; - if (!is_null($address->$areaName) && isset($databases[$area])) { - $extra = (isset($extras[$area]) ? $extras[$area]['administrativeAreaName'] : false); + $where_types = array(); + foreach ($component['types'] as $type) { + $where_types[] = XDB::format('FIND_IN_SET({?}, types)', $type); + } - $res = XDB::query('SELECT id, nameLocal - FROM ' . $databases[$area] . ' - WHERE name = {?}', - $address->$areaName); - if ($res->numRows() == 0) { - XDB::execute('INSERT INTO ' . $databases[$area] . ' (name, nameLocal, country' . - ($extra ? ', ' . $extras[$area]['field'] : '') . ') - VALUES ({?}, {?}, {?}' . ($extra ? ', {?}' : '') . ')', - $address->$areaName, $address->$areaNameLocal, $address->countryId, - ($extra ? $address->$extra : null)); - $address->$areaId = XDB::insertId(); - } else { - // XXX: remove this once all areas have both nameLocal and name. - list($id, $name) = $res->fetchOneRow(); - if (is_null($name) && !is_null($address->$areaNameLocal)) { - XDB::execute('UPDATE ' . $databases[$area] . ' - SET nameLocal = {?} - WHERE id = {?}', - $address->$areaNameLocal, $id); - } - $address->$areaId = $id; - } - } elseif (empty($address->$areaId)) { - $address->$areaId = null; + $id = XDB::fetchOneCell('SELECT id + FROM profile_addresses_components_enum + WHERE short_name = {?} AND long_name = {?} AND ' . implode(' AND ', $where_types), + $component['short_name'], $component['long_name']); + if (is_null($id)) { + XDB::execute('INSERT INTO profile_addresses_components_enum (short_name, long_name, types) + VALUES ({?}, {?}, {?})', + $component['short_name'], $component['long_name'], implode(',', $component['types'])); + $id = XDB::insertId(); } + return $id; } // Returns the part of the text preceeding the line with the postal code @@ -101,24 +73,6 @@ abstract class Geocoder { } return $firstLines; } - - // Returns the number of non geocoded addresses for a user. - static public function countNonGeocoded($pid, $jobid = null, $type = Address::LINK_PROFILE) - { - $where = array(); - if (!is_null($pid)) { - $where[] = XDB::format('pid = {?}', $pid); - } - if (!is_null($jobid)) { - $where[] = XDB::format('jobid = {?}', $jobid); - } - $where[] = XDB::format('FIND_IN_SET({?}, type) AND accuracy = 0', $type); - $res = XDB::query('SELECT COUNT(*) - FROM profile_addresses - WHERE ' . implode(' AND ', $where), - $pid); - return $res->fetchOneCell(); - } } // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: diff --git a/classes/gmapsgeocoder.php b/classes/gmapsgeocoder.php index ec42adf..9378c1b 100644 --- a/classes/gmapsgeocoder.php +++ b/classes/gmapsgeocoder.php @@ -19,28 +19,22 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ***************************************************************************/ -// Implementation of a Geocoder using the Google Maps API. Please refer to -// the following links for details: -// http://code.google.com/apis/maps/documentation/services.html#Geocoding -// http://code.google.com/intl/en/apis/maps/documentation/geocoding/ -// http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy +// Implementation of a Geocoder using the Google Maps API v3. Please refer +// to the following link for details: +// http://code.google.com/apis/maps/documentation/geocoding/ // -// It requires the properties gmaps_key and gmaps_url to be defined in section -// Geocoder in plat/al's configuration (platal.ini & platal.conf). +// It requires the properties gmaps_url to be defined in section Geocoder +// in plat/al's configuration (platal.ini & platal.conf). class GMapsGeocoder extends Geocoder { // Maximum number of Geocoding calls to the Google Maps API. const MAX_GMAPS_RPC_CALLS = 5; - // Maximum levenshtein distance authorized between input and geocoded text in a single line. - const MAX_LINE_DISTANCE = 5; - // Maximum levenshtein distance authorized between input and geocoded text in the whole text. - const MAX_TOTAL_DISTANCE = 6; public function getGeocodedAddress(Address $address, $defaultLanguage = null, $forceLanguage = false) { $this->prepareAddress($address); $textAddress = $this->getTextToGeocode($address->text); if (is_null($defaultLanguage)) { - $defaultLanguage = Platal::globals()->geocoder->gmaps_hl; + $defaultLanguage = Platal::globals()->geocoder->gmaps_language; } // Try to geocode the full address. @@ -66,16 +60,16 @@ class GMapsGeocoder extends Geocoder { } public function stripGeocodingFromAddress(Address $address) { - $address->geocodedText = null; - $address->geoloc_choice = null; - $address->countryId = null; - $address->country = null; - $address->administrativeAreaName = null; - $address->subAdministrativeAreaName = null; - $address->localityName = null; - $address->thoroughfareName = null; - $address->postalCode = null; - $address->accuracy = 0; + $address->formatted_address = ''; + $address->types = ''; + $address->latitude = null; + $address->longitude = null; + $address->southwest_latitude = null; + $address->southwest_longitude = null; + $address->northeast_latitude = null; + $address->northeast_longitude = null; + $address->location_type = null; + $address->partial_match = false; } // Updates the address with the geocoded information from Google Maps. Also @@ -92,7 +86,7 @@ class GMapsGeocoder extends Geocoder { $url = $this->getGeocodingUrl($address, $defaultLanguage); $geoData = $this->getGeoJsonFromUrl($url); - return ($geoData ? $this->getPlacemarkFromJson($geoData) : null); + return ($geoData ? $this->getPlacemarkFromJson($geoData, $url) : null); } // Prepares address to be geocoded @@ -106,16 +100,13 @@ class GMapsGeocoder extends Geocoder { global $globals; $parameters = array( - 'key' => $globals->geocoder->gmaps_key, - 'sensor' => 'false', // The queried address wasn't obtained from a GPS sensor. - 'hl' => $defaultLanguage, - 'oe' => 'utf8', // Output encoding. - 'output' => 'json', // Output format. - 'gl' => $globals->geocoder->gmaps_gl, - 'q' => $address, // The queries address. + 'language' => $defaultLanguage, + 'region' => $globals->geocoder->gmaps_region, + 'sensor' => 'false', // The queried address wasn't obtained from a GPS sensor. + 'address' => $address, // The queries address. ); - return $globals->geocoder->gmaps_url . '?' . http_build_query($parameters); + return $globals->geocoder->gmaps_url . 'json?' . http_build_query($parameters); } // Fetches JSON-encoded data from a Google Maps API url, and decode them. @@ -152,131 +143,43 @@ class GMapsGeocoder extends Geocoder { } // Extracts the most appropriate placemark from the JSON data fetched from - // Google Maps. Returns a Placemark array on success, and null otherwise. See - // http://code.google.com/apis/maps/documentation/services.html#Geocoding_Structured - // for details on the Placemark structure. - private function getPlacemarkFromJson(array $data) { - // Check for geocoding failures. - if (!isset($data['Status']['code']) || $data['Status']['code'] != 200) { - // TODO: handle non-200 codes in a better way, since the code might - // indicate a temporary error on Google's side. + // Google Maps. Returns a Placemark array on success, and null otherwise. + // http://code.google.com/apis/maps/documentation/geocoding/#StatusCodes + private function getPlacemarkFromJson(array $data, $url) { + // Check for geocoding status. + $status = $data['status']; + + // If no result, return null. + if ($status == 'ZERO_RESULTS') { return null; } - // Check that at least one placemark was found. - if (count($data['Placemark']) == 0) { - return null; + // If there are results return the first one. + if ($status == 'OK') { + return $data['results'][0]; } - // Extract the placemark with the best accuracy. This is not always the - // best result (since the same address may yield two different placemarks). - $result = $data['Placemark'][0]; - foreach ($data['Placemark'] as $place) { - if ($place['AddressDetails']['Accuracy'] > $result['AddressDetails']['Accuracy']) { - $result = $place; - } - } - - return $result; + // Report the error. + $mailer = new PlMailer('profile/geocoding.mail.tpl'); + $mailer->assign('status', $status); + $mailer->assign('url', $url); + $mailer->send(); + return null; } // Fills the address with the geocoded data private function fillAddressWithGeocoding(Address $address, $geocodedData, $isLocal) { - // The geocoded address three is - // Country -> AdministrativeArea -> SubAdministrativeArea -> Locality -> Thoroughfare - // with all the possible shortcuts - // The address is formatted as xAL, or eXtensible Address Language, an international - // standard for address formatting. - // xAL documentation: http://www.oasis-open.org/committees/ciq/ciq.html#6 - if ($isLocal) { - $ext = 'Local'; - } else { - $ext = ucfirst(Platal::globals()->geocoder->gmaps_hl); - $address->geocodedText = str_replace(', ', "\n", $geocodedData['address']); - } - - if (isset($geocodedData['AddressDetails']['Accuracy'])) { - $address->accuracy = $geocodedData['AddressDetails']['Accuracy']; - } - - $currentPosition = $geocodedData['AddressDetails']; - if (isset($currentPosition['Country'])) { - $country = 'country' . $ext; - $currentPosition = $currentPosition['Country']; - $address->countryId = $currentPosition['CountryNameCode']; - $address->$country = $currentPosition['CountryName']; - } - if (isset($currentPosition['AdministrativeArea'])) { - $administrativeAreaName = 'administrativeAreaName' . $ext; - $currentPosition = $currentPosition['AdministrativeArea']; - $address->$administrativeAreaName = $currentPosition['AdministrativeAreaName']; - } - if (isset($currentPosition['SubAdministrativeArea'])) { - $subAdministrativeAreaName = 'subAdministrativeAreaName' . $ext; - $currentPosition = $currentPosition['SubAdministrativeArea']; - $address->$subAdministrativeAreaName = $currentPosition['SubAdministrativeAreaName']; - } - if (isset($currentPosition['Locality'])) { - $localityName = 'localityName' . $ext; - $currentPosition = $currentPosition['Locality']; - $address->$localityName = $currentPosition['LocalityName']; - } - if (isset($currentPosition['PostalCode'])) { - $address->postalCode = $currentPosition['PostalCode']['PostalCodeNumber']; - } - - // Gets coordinates. - if (isset($geocodedData['Point']['coordinates'][0])) { - $address->latitude = $geocodedData['Point']['coordinates'][0]; - } - if (isset($geocodedData['Point']['coordinates'][1])) { - $address->longitude = $geocodedData['Point']['coordinates'][1]; - } - if (isset($geocodedData['ExtendedData']['LatLonBox']['north'])) { - $address->north = $geocodedData['ExtendedData']['LatLonBox']['north']; - } - if (isset($geocodedData['ExtendedData']['LatLonBox']['south'])) { - $address->south = $geocodedData['ExtendedData']['LatLonBox']['south']; - } - if (isset($geocodedData['ExtendedData']['LatLonBox']['east'])) { - $address->east = $geocodedData['ExtendedData']['LatLonBox']['east']; - } - if (isset($geocodedData['ExtendedData']['LatLonBox']['west'])) { - $address->west = $geocodedData['ExtendedData']['LatLonBox']['west']; - } - } - - // Compares the geocoded address with the given address and returns true - // iff their are close enough to be considered as equals or not. - private function compareAddress($address) - { - $same = true; - $geoloc = strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"), - array('', "\n"), $address->geocodedText)); - $text = strtoupper(preg_replace(array("/[0-9,\"'#~:;_\- ]/", "/\r\n/"), - array('', "\n"), $address->text)); - $arrayGeoloc = explode("\n", $geoloc); - $arrayText = explode("\n", $text); - $countGeoloc = count($arrayGeoloc); - $countText = count($arrayText); - - $totalDistance = 0; - if (($countText > $countGeoloc) || ($countText < $countGeoloc - 1) - || (($countText == $countGeoloc - 1) - && ($arrayText[$countText - 1] == strtoupper($address->country)))) { - $same = false; - } else { - for ($i = 0; $i < $countGeoloc && $i < $countText; ++$i) { - $lineDistance = levenshtein($arrayText[$i], trim($arrayGeoloc[$i])); - $totalDistance += $lineDistance; - if ($lineDistance > self::MAX_LINE_DISTANCE || $totalDistance > self::MAX_TOTAL_DISTANCE) { - $same = false; - break; - } - } - } - - return $same; + $address->types = implode(',', $geocodedData['types']); + $address->formatted_address = $geocodedData['formatted_address']; + $address->components = $geocodedData['address_components']; + $address->latitude = $geocodedData['geometry']['location']['lat']; + $address->longitude = $geocodedData['geometry']['location']['lng']; + $address->southwest_latitude = $geocodedData['geometry']['viewport']['southwest']['lat']; + $address->southwest_longitude = $geocodedData['geometry']['viewport']['southwest']['lng']; + $address->northeast_latitude = $geocodedData['geometry']['viewport']['northeast']['lat']; + $address->northeast_longitude = $geocodedData['geometry']['viewport']['northeast']['lng']; + $address->location_type = $geocodedData['geometry']['location_type']; + $address->partial_match = isset($geocodedData['partial_match']) ? true : false; } // Formats the text of the geocoded address using the unused data and @@ -284,13 +187,8 @@ class GMapsGeocoder extends Geocoder { // will be asked to choose between them. private function formatAddress(Address $address, $extraLines, $forceLanguage) { - if ($extraLines) { - $address->geocodedText = $extraLines . "\n" . $address->geocodedText; - } - - if ($this->compareAddress($address)) { - $address->geocodedText = null; - } elseif (!$forceLanguage) { + /* XXX: Check how to integrate this in the new geocoding system. + if (!$forceLanguage) { $languages = XDB::fetchOneCell('SELECT IF(ISNULL(gc1.belongsTo), gl1.language, gl2.language) FROM geoloc_countries AS gc1 INNER JOIN geoloc_languages AS gl1 ON (gc1.iso_3166_1_a2 = gl1.iso_3166_1_a2) @@ -300,21 +198,13 @@ class GMapsGeocoder extends Geocoder { $address->countryId); $toGeocode = substr($address->text, strlen($extraLines)); foreach (explode(',', $languages) as $language) { - if ($language != Platal::globals()->geocoder->gmaps_hl) { + if ($language != Platal::globals()->geocoder->gmaps_language) { $geocodedData = $this->getPlacemarkForAddress($toGeocode, $language); - $address->geocodedText = str_replace(', ', "\n", $geocodedData['address']); - if ($extraLines) { - $address->geocodedText = $extraLines . "\n" . $address->geocodedText; - } - if ($this->compareAddress($address)) { - $this->fillAddressWithGeocoding($address, $geocodedData, true); - $address->geocodedText = null; - break; - } + $this->fillAddressWithGeocoding($address, $geocodedData, true); + break; } } - $address->geocodedText = str_replace("\n", "\r\n", $address->geocodedText); - } + }*/ $address->text = str_replace("\n", "\r\n", $address->text); } diff --git a/configs/mails.conf b/configs/mails.conf index d17d066..06fc744 100644 --- a/configs/mails.conf +++ b/configs/mails.conf @@ -34,7 +34,7 @@ to=hotliners@staff.polytechnique.org [geoloc_error] from=webmaster@polytechnique.org -to=non-geoloc@staff.polytechnique.org +to=br@staff.polytechnique.org [mails_ax] from="Amicale des Anciens de l'X" diff --git a/configs/platal.ini b/configs/platal.ini index a057415..f4e7e78 100644 --- a/configs/platal.ini +++ b/configs/platal.ini @@ -216,21 +216,17 @@ event_reply = "" ; Unused parameter. email = "" -; $globals->geocoder->gmaps_key -; API key to use when querying google maps web service -gmaps_key = "" - ; $globals->geocoder->gmaps_url ; URL of geocoding webservice -gmaps_url = "http://maps.google.com/maps/geo" +gmaps_url = "https://maps.googleapis.com/maps/api/geocode/" -; $globals->geocoder->gmaps_hl +; $globals->geocoder->gmaps_language ; Default output language. -gmaps_hl = "fr" +gmaps_language = "fr" -; $globals->geocoder->gmaps_gl +; $globals->geocoder->gmaps_region ; Default location preference. -gmaps_gl = "fr" +gmaps_region = "fr" ; The lists section contains parameters used to interact with mailman. diff --git a/templates/geoloc/form.address.tpl b/templates/geoloc/form.address.tpl index a41cd4f..033c3c0 100644 --- a/templates/geoloc/form.address.tpl +++ b/templates/geoloc/form.address.tpl @@ -23,25 +23,24 @@ - - - - - - + + - - - - + + + + + + + {if t($address.latitude)} - Position de l'adresse
{icon name=cross title="Adresse mal localisée"} Signaler que le repère est mal placé diff --git a/templates/profile/geocoding.mail.tpl b/templates/profile/geocoding.mail.tpl index 1637b19..5df456d 100644 --- a/templates/profile/geocoding.mail.tpl +++ b/templates/profile/geocoding.mail.tpl @@ -24,16 +24,14 @@ {if $mail_part eq 'head'} {from full=#from#} {to addr=#to#} -{subject text="Adresse impossible à geolocaliser"} +{subject text="Erreur de géolocalisation"} {elseif $mail_part eq 'wiki'} -Un camarade {$smarty.session.hruid} a forcé l'utilisation de l'adresse entrée -à la main et a refusé la version geolocalisée : +La requête de géocodage générée par {$smarty.session.hruid} et dont l'url +est la suivante :\\ +{$url}\\ +a reçu le status d'erreur suivant :\\ +{$status} -'''Version utilisateur (validée) :'''\\ -{$text} - -'''Version geoloc (refusée) :'''\\ -{$geoloc} {include file="include/signature.mail.tpl"} {/if} diff --git a/upgrade/1.1.2/01_geocoding.sql b/upgrade/1.1.2/01_geocoding.sql new file mode 100644 index 0000000..b89083d --- /dev/null +++ b/upgrade/1.1.2/01_geocoding.sql @@ -0,0 +1,59 @@ +DROP TABLE IF EXISTS profile_addresses_components; +DROP TABLE IF EXISTS profile_addresses_components_enum; + +CREATE TABLE profile_addresses_components_enum ( + id BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + short_name VARCHAR(255) NOT NULL DEFAULT '', + long_name VARCHAR(255) NOT NULL DEFAULT '', + types SET('street_address', 'route', 'intersection', 'political', 'country', 'administrative_area_level_1', 'administrative_area_level_2', 'administrative_area_level_3', 'colloquial_area', 'locality', 'sublocality', 'neighborhood', 'premise', 'subpremise', 'postal_code', 'natural_feature', 'airport', 'park', 'point_of_interest', 'post_box', 'street_number', 'floor', 'room') NOT NULL DEFAULT '', + PRIMARY KEY (id), + UNIQUE KEY (types, long_name), + KEY (types, short_name) +) ENGINE=InnoDB, CHARSET=utf8; + +CREATE TABLE profile_addresses_components ( + pid INT(11) UNSIGNED NOT NULL DEFAULT 0, + jobid INT(6) UNSIGNED NOT NULL DEFAULT 0, + groupid SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0, + type ENUM('home', 'job', 'hq', 'group') NOT NULL DEFAULT 'home', + id TINYINT(3) UNSIGNED NOT NULL DEFAULT 0, + component_id BIGINT(10) UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (pid, jobid, groupid, type, id, component_id), + KEY(component_id), + FOREIGN KEY (pid, jobid, groupid, type, id) REFERENCES profile_addresses (pid, jobid, groupid, type, id) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (component_id) REFERENCES profile_addresses_components_enum (id) ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB, CHARSET=utf8; + +ALTER TABLE profile_addresses DROP FOREIGN KEY profile_addresses_ibfk_1; +ALTER TABLE profile_addresses DROP FOREIGN KEY profile_addresses_ibfk_2; +ALTER TABLE profile_addresses DROP FOREIGN KEY profile_addresses_ibfk_3; +ALTER TABLE profile_addresses DROP FOREIGN KEY profile_addresses_ibfk_4; + +ALTER TABLE profile_addresses DROP COLUMN accuracy; +ALTER TABLE profile_addresses DROP COLUMN postalCode; +ALTER TABLE profile_addresses DROP COLUMN localityId; +ALTER TABLE profile_addresses DROP COLUMN subAdministrativeAreaId; +ALTER TABLE profile_addresses DROP COLUMN administrativeAreaId; +ALTER TABLE profile_addresses DROP COLUMN countryId; +ALTER TABLE profile_addresses DROP COLUMN north; +ALTER TABLE profile_addresses DROP COLUMN south; +ALTER TABLE profile_addresses DROP COLUMN east; +ALTER TABLE profile_addresses DROP COLUMN west; + +ALTER TABLE profile_addresses ADD COLUMN formatted_address TEXT NOT NULL DEFAULT '' AFTER postalText; +ALTER TABLE profile_addresses ADD COLUMN types SET('street_address', 'route', 'intersection', 'political', 'country', 'administrative_area_level_1', 'administrative_area_level_2', 'administrative_area_level_3', 'colloquial_area', 'locality', 'sublocality', 'neighborhood', 'premise', 'subpremise', 'postal_code', 'natural_feature', 'airport', 'park', 'point_of_interest', 'post_box', 'street_number', 'floor', 'room') NOT NULL DEFAULT '' AFTER formatted_address; +ALTER TABLE profile_addresses ADD COLUMN southwest_latitude FLOAT(10, 7) DEFAULT NULL AFTER longitude; +ALTER TABLE profile_addresses ADD COLUMN southwest_longitude FLOAT(10, 7) DEFAULT NULL AFTER southwest_latitude; +ALTER TABLE profile_addresses ADD COLUMN northeast_latitude FLOAT(10, 7) DEFAULT NULL AFTER southwest_longitude; +ALTER TABLE profile_addresses ADD COLUMN northeast_longitude FLOAT(10, 7) DEFAULT NULL AFTER northeast_latitude; +ALTER TABLE profile_addresses ADD COLUMN location_type ENUM('ROOFTOP', 'RANGE_INTERPOLATED', 'GEOMETRIC_CENTER', 'APPROXIMATE') DEFAULT NULL AFTER northeast_longitude; +ALTER TABLE profile_addresses ADD COLUMN partial_match BOOLEAN NOT NULL DEFAULT false AFTER location_type; + +UPDATE profile_addresses + SET latitude = NULL, longitude = NULL; + +DROP TABLE IF EXISTS geoloc_administrativeareas; +DROP TABLE IF EXISTS geoloc_localities; +DROP TABLE IF EXISTS geoloc_subadministrativeareas; + +-- vim:set syntax=mysql: -- 2.1.4