From 9c983c383029c9aaa7d0cf04a5fc9973d514dff7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 22 Oct 2009 15:44:36 -0400 Subject: extract Geonames stuff to a plugin --- plugins/GeonamesPlugin.php | 281 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 plugins/GeonamesPlugin.php (limited to 'plugins/GeonamesPlugin.php') diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php new file mode 100644 index 000000000..934e998c7 --- /dev/null +++ b/plugins/GeonamesPlugin.php @@ -0,0 +1,281 @@ +. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Plugin to convert string locations to Geonames IDs and vice versa + * + * This handles most of the events that Location class emits. It uses + * the geonames.org Web service to convert names like 'Montreal, Quebec, Canada' + * into IDs and lat/lon pairs. + * + * @category Plugin + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @seeAlso Location + */ + +class GeonamesPlugin extends Plugin +{ + const NAMESPACE = 1; + + /** + * convert a name into a Location object + * + * @param string $name Name to convert + * @param string $language ISO code for anguage the name is in + * @param Location &$location Location object (may be null) + * + * @return boolean whether to continue (results in $location) + */ + + function onLocationFromName($name, $language, &$location) + { + $client = HTTPClient::start(); + + // XXX: break down a name by commas, narrow by each + + $str = http_build_query(array('maxRows' => 1, + 'q' => $name, + 'lang' => $language, + 'type' => 'json')); + + $result = $client->get('http://ws.geonames.org/search?'.$str); + + if ($result->code == "200") { + $rj = json_decode($result->body); + if (count($rj['geonames']) > 0) { + $n = $rj['geonames'][0]; + + $location = new Location(); + + $location->lat = $n['lat']; + $location->lon = $n['lng']; + $location->names[$language] = $n['name']; + $location->location_id = $n['geonameId']; + $location->location_ns = self::NAMESPACE; + + // handled, don't continue processing! + return false; + } + } + + // Continue processing; we don't have the answer + return true; + } + + /** + * convert an id into a Location object + * + * @param string $id Name to convert + * @param string $ns Name to convert + * @param string $language ISO code for language for results + * @param Location &$location Location object (may be null) + * + * @return boolean whether to continue (results in $location) + */ + + function onLocationFromId($id, $ns, $language, &$location) + { + if ($ns != self::NAMESPACE) { + // It's not one of our IDs... keep processing + return true; + } + + $client = HTTPClient::start(); + + $str = http_build_query(array('geonameId' => $id, + 'lang' => $language)); + + $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str); + + if ($result->code == "200") { + + $rj = json_decode($result->body); + + if (count($rj['geonames']) > 0) { + + $parts = array(); + + foreach ($rj['geonames'] as $level) { + if (in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $level['name']; + } + } + + $last = $rj['geonames'][count($rj['geonames'])-1]; + + if (!in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $last['name']; + } + + $location = new Location(); + + $location->location_id = $last['geonameId']; + $location->location_ns = self::NAMESPACE; + $location->lat = $last['lat']; + $location->lon = $last['lng']; + $location->names[$language] = implode(', ', array_reverse($parts)); + } + } + + // We're responsible for this NAMESPACE; nobody else + // can resolve it + + return false; + } + + /** + * convert a lat/lon pair into a Location object + * + * Given a lat/lon, we try to find a Location that's around + * it or nearby. We prefer populated places (cities, towns, villages). + * + * @param string $lat Latitude + * @param string $lon Longitude + * @param string $language ISO code for language for results + * @param Location &$location Location object (may be null) + * + * @return boolean whether to continue (results in $location) + */ + + function onLocationFromLatLon($lat, $lon, $language, &$location) + { + $client = HTTPClient::start(); + + $str = http_build_query(array('lat' => $lat, + 'lng' => $lon, + 'lang' => $language)); + + $result = + $client->get('http://ws.geonames.org/findNearbyPlaceNameJSON?'.$str); + + if ($result->code == "200") { + + $rj = json_decode($result->body); + + if (count($rj['geonames']) > 0) { + + $n = $rj['geonames'][0]; + + $parts = array(); + + $location = new Location(); + + $parts[] = $n['name']; + + if (!empty($n['adminName1'])) { + $parts[] = $n['adminName1']; + } + + if (!empty($n['countryName'])) { + $parts[] = $n['countryName']; + } + + $location->location_id = $n['geonameId']; + $location->location_ns = self::NAMESPACE; + $location->lat = $lat; + $location->lon = $lon; + + $location->names[$language] = implode(', ', $parts); + + // Success! We handled it, so no further processing + + return false; + } + } + + // For some reason we don't know, so pass. + + return true; + } + + /** + * Human-readable name for a location + * + * Given a location, we try to retrieve a human-readable name + * in the target language. + * + * @param Location $location Location to get the name for + * @param string $language ISO code for language to find name in + * @param string &$name Place to put the name + * + * @return boolean whether to continue + */ + + function onLocationNameLanguage($location, $language, &$name) + { + if ($location->location_ns != self::NAMESPACE) { + // It's not one of our IDs... keep processing + return true; + } + + $client = HTTPClient::start(); + + $str = http_build_query(array('geonameId' => $id, + 'lang' => $language)); + + $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str); + + if ($result->code == "200") { + + $rj = json_decode($result->body); + + if (count($rj['geonames']) > 0) { + + $parts = array(); + + foreach ($rj['geonames'] as $level) { + if (in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $level['name']; + } + } + + $last = $rj['geonames'][count($rj['geonames'])-1]; + + if (!in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $last['name']; + } + + if (count($parts)) { + $name = implode(', ', array_reverse($parts)); + return false; + } + } + } + + return true; + } +} -- cgit v1.2.3-54-g00ecf From de4b2098d1a73734f94dd4a2c5395857fb6afa89 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 22 Oct 2009 16:20:31 -0400 Subject: results of json parsing are objects not arrays --- plugins/GeonamesPlugin.php | 62 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'plugins/GeonamesPlugin.php') diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php index 934e998c7..745cd4126 100644 --- a/plugins/GeonamesPlugin.php +++ b/plugins/GeonamesPlugin.php @@ -76,15 +76,15 @@ class GeonamesPlugin extends Plugin if ($result->code == "200") { $rj = json_decode($result->body); - if (count($rj['geonames']) > 0) { - $n = $rj['geonames'][0]; + if (count($rj->geonames) > 0) { + $n = $rj->geonames[0]; $location = new Location(); - $location->lat = $n['lat']; - $location->lon = $n['lng']; - $location->names[$language] = $n['name']; - $location->location_id = $n['geonameId']; + $location->lat = $n->lat; + $location->lon = $n->lng; + $location->names[$language] = $n->name; + $location->location_id = $n->geonameId; $location->location_ns = self::NAMESPACE; // handled, don't continue processing! @@ -125,28 +125,28 @@ class GeonamesPlugin extends Plugin $rj = json_decode($result->body); - if (count($rj['geonames']) > 0) { + if (count($rj->geonames) > 0) { $parts = array(); - foreach ($rj['geonames'] as $level) { - if (in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $level['name']; + foreach ($rj->geonames as $level) { + if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $level->name; } } - $last = $rj['geonames'][count($rj['geonames'])-1]; + $last = $rj->geonames[count($rj->geonames)-1]; - if (!in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $last['name']; + if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $last->name; } $location = new Location(); - $location->location_id = $last['geonameId']; + $location->location_id = $last->geonameId; $location->location_ns = self::NAMESPACE; - $location->lat = $last['lat']; - $location->lon = $last['lng']; + $location->lat = $last->lat; + $location->lon = $last->lng; $location->names[$language] = implode(', ', array_reverse($parts)); } } @@ -186,25 +186,25 @@ class GeonamesPlugin extends Plugin $rj = json_decode($result->body); - if (count($rj['geonames']) > 0) { + if (count($rj->geonames) > 0) { - $n = $rj['geonames'][0]; + $n = $rj->geonames[0]; $parts = array(); $location = new Location(); - $parts[] = $n['name']; + $parts[] = $n->name; - if (!empty($n['adminName1'])) { - $parts[] = $n['adminName1']; + if (!empty($n->adminName1)) { + $parts[] = $n->adminName1; } - if (!empty($n['countryName'])) { - $parts[] = $n['countryName']; + if (!empty($n->countryName)) { + $parts[] = $n->countryName; } - $location->location_id = $n['geonameId']; + $location->location_id = $n->geonameId; $location->location_ns = self::NAMESPACE; $location->lat = $lat; $location->lon = $lon; @@ -253,20 +253,20 @@ class GeonamesPlugin extends Plugin $rj = json_decode($result->body); - if (count($rj['geonames']) > 0) { + if (count($rj->geonames) > 0) { $parts = array(); - foreach ($rj['geonames'] as $level) { - if (in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $level['name']; + foreach ($rj->geonames as $level) { + if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $level->name; } } - $last = $rj['geonames'][count($rj['geonames'])-1]; + $last = $rj->geonames[count($rj->geonames)-1]; - if (!in_array($level['fcode'], array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $last['name']; + if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = $last->name; } if (count($parts)) { -- cgit v1.2.3-54-g00ecf From 62ba14f5cf54235a0929d2ab06b62bad02ff7241 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 29 Oct 2009 15:07:26 -0400 Subject: make an URL for a geonames location --- plugins/GeonamesPlugin.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'plugins/GeonamesPlugin.php') diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php index 745cd4126..80ef44cc9 100644 --- a/plugins/GeonamesPlugin.php +++ b/plugins/GeonamesPlugin.php @@ -278,4 +278,28 @@ class GeonamesPlugin extends Plugin return true; } + + /** + * Human-readable name for a location + * + * Given a location, we try to retrieve a geonames.org URL. + * + * @param Location $location Location to get the url for + * @param string &$url Place to put the url + * + * @return boolean whether to continue + */ + + function onLocationUrl($location, &$url) + { + if ($location->location_ns != self::NAMESPACE) { + // It's not one of our IDs... keep processing + return true; + } + + $url = 'http://www.geonames.org/' . $location->location_id; + + // it's been filled, so don't process further. + return false; + } } -- cgit v1.2.3-54-g00ecf