Disambiguate location information using Yahoo! Placemaker component

This article is also available in the following languages:
By prashant_patil
This component uses Yahoo Placemaker service to disambiguate location information and return the best match with a geo marker.
e.g. input: big apple => output: [locationType]=town,[name] =>New York, NY [latitude] => 40.7146 [longitude] => -74.0071
While building web applications, many times we come across a feature where we have to take location information from user to search a database or query a webservice. e.g. the ‘Locate Store’ feature on many retailer web sites. While building this feature normally we ask the user to either enter a city name and state name OR enter a zip code. But using the placemaker component you can just ask the users to enter the location information in a free form (like for New York City, user can enter ‘NYC’ or ‘Big Apple’). This component will disambiguate the user input and provide you the best match with a geo marker (latitude and longitude).
More information about Yahoo Placemaker service can be found at http://developer.yahoo.com/geo/placemaker/

The Component




<?php
/**
 * This is the Yahoo Placemaker Component Class to disambiguate the place name
 * and returns the best matches with a geomarker
 *
 * Requires PHP5 (simple xml) and the cURL library 
 * 
 * @author    Prashant Patil
 * @version 1.0
 * @link http://developer.yahoo.com/geo/placemaker/
 * @category Components 
 */
class PlacemakerComponent extends Object {
  
    
/**
     * Yahoo Place Make WebService
     */ 
    
protected $ypHost 'http://wherein.yahooapis.com/v1/document';
    
/**
     * Yahoo Application ID for Yahoo Developer Network
     * @link https://developer.apps.yahoo.com/wsregapp/
     */ 
    
protected $ypAppId '';
    
/**
     * Variable to store the error generated during the operation
     */
    
protected $lastError '';
    
/**
     * the suffix is used to get the location info within United States
     */
    
protected $suffixUsed ', US';

    
    
//called before Controller::beforeFilter()
    
function initialize(&$controller$settings = array()) {
        
// saving the controller reference for later use
        
$this->controller =& $controller;
        
        if(isset(
$settings['appid']))
        {
            
$this->ypAppId $settings['appid'];
        }
    }

    
//called after Controller::beforeFilter()
    
function startup(&$controller) {
    }
    
    
/**
     * Method to get the locationinfo for a place
     * 
     * @param string $locationName
     * @return array Location info or error
     */
    
public function getLocationInfo($locationName)
    {
      
$stateArray = array();
      
$townArray = array();
      
$suburbArray = array();
      
$zipArray = array();
      
      
$locationType '';
      
      
$returnData = array('error'=>0,
                          
'errorMessage'=>'',
                          
'locationDetails'=>array());
      
$locationName strip_tags(trim($locationName));
      
$tmpLocations = array();
      
      try
      {   
          if(
$ypResponse $this->_ypCall($locationName))
          {  
            if(
$simpleXml simplexml_load_string($ypResponse))
            {
              if(
$simpleXml instanceof SimpleXMLElement)
              {
                if(isset(
$simpleXml->document->placeDetails))
                {
                    foreach (
$simpleXml->document->placeDetails as $place)
                    { 
                       
$data['name']= str_replace($this->suffixUsed,'',trim((string)$place->place->name));
                       
$data['latitude']= (string)$place->place->centroid->latitude;
                       
$data['longitude']= (string)$place->place->centroid->longitude;
                       
                      
// To avoid the duplicate data
                      // for location Monroe, LA Yahoo Placemaker returns two locations with same name 
                      
if(!in_array($data['name'],$tmpLocations))
                      {
                          
$tmpLocations[]=$data['name'];
                           
                          switch (
strtolower((string)$place->place->type))
                          {
                            case 
'state':
                              
$stateArray[]=$data;
                              break;  
// End foreach Loop also since we found a state
                            
case 'town':
                              
$townArray[]=$data;
                              break;
                            case 
'zip':
                              
$zipArray[]=$data;
                              break;
                            case 
'suburb':
                              
$suburbArray[]=$data;
                              break;
                          }
                      }
                      
                    }
                    
                    
//If State is found just return the state info
                    
if(sizeof($stateArray)>0)
                    {
                      
$returnData['locationDetails']['locationType'] = 'state';
                      
$returnData['locationDetails']['locations'] = $stateArray;
                    }
                    
// if zip is found just return zip info
                    
elseif(sizeof($zipArray)>0)
                    {
                      
$returnData['locationDetails']['locationType'] = 'zip';
                      
$returnData['locationDetails']['locations'] = $zipArray;
                    }
                    elseif(
sizeof($townArray)>0)
                    {
                      
$returnData['locationDetails']['locationType'] = 'town';
                      
$returnData['locationDetails']['locations'] = $townArray;
                    }
                }
                else
                {
                  
//If placeDetails Element is not found
                  
throw new Exception('Can not find place details');
                }
              }
              else
              {
                
// Not able to create simpleXmlElement object from Response XML
                
throw new Exception('Can not create the SimpleXMLElement object');
              }
                  
            }
            else
            {
              
// Not a valid response from the Yahoo Placemaker service
              
throw new Exception('Not a valid XML Response');
            }
           
          }
          else
          {
            
// Not a valid response from the Yahoo Placemaker service
            
throw new Exception($this->lastError);
          }
      }
      catch (
Exception $e)
      {
        
$returnData = array('error'=> 1,
                          
'errorMessage'=> $e->getMessage(),
                          
'locationDetails' => null);
      }
      return 
$returnData;
    }
    
    
/**
     * Method to get last error generated during the call
     */
    
public function getLastError()
    {
      return 
$this->lastError;
    }
    
    
/**
     * Method to send request and receive the response from Yahoo webservice
     * 
     * @param string $locationName
     * @return string 
     */
    
protected function _ypCall($locationName)
    { 
      
$ch curl_init();
      
      
$data = array(
                      
'documentContent'=>$locationName.$this->suffixUsed,
                    
'documentType'=>'text/plain',
                    
'outputType'=>'xml',
                    
'autoDisambiguate' => 'false'
                    
//'focusWoeid'=>'23424977',
                    
'appid'=>$this->ypAppId);
      
      
curl_setopt($chCURLOPT_URL$this->ypHost);
      
curl_setopt($chCURLOPT_POST1);
      
curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
      
curl_setopt($chCURLOPT_CONNECTTIMEOUT,10);
      
curl_setopt($chCURLOPT_FAILONERROR1);
      
curl_setopt($chCURLOPT_HEADER0);
      
curl_setopt($chCURLOPT_POSTFIELDS$data);
      
      
$output curl_exec($ch);
      
      if(
curl_errno($ch))
      {
         
$this->lastError 'Curl error: ' curl_error($ch);
         
$output false;
      }
      else
      {
         
$this->lastError '';
      }
      
curl_close($ch);
      return 
$output;
    }    
}
?>


once you put this component in your app/controllers/components directory (as placemaker.php). Use following steps to use it in your controller.


<?php

class PagesController extends AppController {
        var 
$components = array('placemaker'=>array('appid'=>'your Yahoo App id goes here'));
        function 
index()     {
            
            
$locInfo $this->placemaker->getLocationInfo($this->data['searcj']['location']);
        }
}
?>

You can get the Yahoo App Id at https://developer.apps.yahoo.com/wsregapp/.
The variable locInfo will be an array which will be of following format


Array
(
    [error] => bit
    [errorMessage] => string 
    [locationDetails] => Array
)

If no locations are found element 'error' will be 1 with appropriate error message.
If the place info is found then element 'locationDetails' will have detail information about the location

[h3]Examples[h3] [h4]input: NYC[h4]
Array
(
    [error] => 0
    [errorMessage] => 
    [locationDetails] => Array
        (
            [locationType] => town
            [locations] => Array
                (
                    [0] => Array
                        (
                            [name] => New York, NY
                            [latitude] => 40.7146
                            [longitude] => -74.0071
                        )

                )

        )

)



[h4]input: 71203[h4]
Array
(
    [error] => 0
    [errorMessage] => 
    [locationDetails] => Array
        (
            [locationType] => zip
            [locations] => Array
                (
                    [0] => Array
                        (
                            [name] => 71203, Monroe, LA
                            [latitude] => 32.5977
                            [longitude] => -92.0323
                        )

                )

        )

)

[h4]input: Monroe, LA[h4]
Array
(
    [error] => 0
    [errorMessage] => 
    [locationDetails] => Array
        (
            [locationType] => town
            [locations] => Array
                (
                    [0] => Array
                        (
                            [name] => Monroe, LA
                            [latitude] => 32.815
                            [longitude] => -92.2056
                        )

                )

        )

)



If multiple locations are found it will return all the possibilities
e.g.
[h4]input: Monroe[h4]
Array
(
    [error] => 0
    [errorMessage] => 
    [locationDetails] => Array
        (
            [locationType] => town
            [locations] => Array
                (
                    [0] => Array
                        (
                            [name] => Lenox Center, OH
                            [latitude] => 41.6802
                            [longitude] => -80.763
                        )

                    [1] => Array
                        (
                            [name] => Monroe, CT
                            [latitude] => 41.3342
                            [longitude] => -73.2061
                        )

                    [2] => Array
                        (
                            [name] => Monroe, IN
                            [latitude] => 40.745
                            [longitude] => -84.937
                        )

                    [3] => Array
                        (
                            [name] => Monroe, KY
                            [latitude] => 37.2333
                            [longitude] => -85.7014
                        )

                    [4] => Array
                        (
                            [name] => Monroe, LA
                            [latitude] => 32.815
                            [longitude] => -92.2056
                        )

                    [5] => Array
                        (
                            [name] => Monroe, ME
                            [latitude] => 44.6155
                            [longitude] => -69.0138
                        )

                    [6] => Array
                        (
                            [name] => Monroe, MS
                            [latitude] => 31.474
                            [longitude] => -90.8287
                        )

                    [7] => Array
                        (
                            [name] => Monroe, NE
                            [latitude] => 41.4751
                            [longitude] => -97.6005
                        )

                    [8] => Array
                        (
                            [name] => Monroe, NH
                            [latitude] => 44.2607
                            [longitude] => -72.0544
                        )

                    [9] => Array
                        (
                            [name] => Monroe, OH
                            [latitude] => 39.4418
                            [longitude] => -84.3624
                        )

                    [10] => Array
                        (
                            [name] => Monroe, OK
                            [latitude] => 34.9946
                            [longitude] => -94.5189
                        )

                    [11] => Array
                        (
                            [name] => Monroe, OR
                            [latitude] => 44.3154
                            [longitude] => -123.297
                        )

                    [12] => Array
                        (
                            [name] => Monroe, PA
                            [latitude] => 41.1217
                            [longitude] => -79.433
                        )

                    [13] => Array
                        (
                            [name] => Monroe, SD
                            [latitude] => 43.4881
                            [longitude] => -97.2129
                        )

                    [14] => Array
                        (
                            [name] => Monroe, TN
                            [latitude] => 36.4399
                            [longitude] => -85.2519
                        )

                    [15] => Array
                        (
                            [name] => Monroe, TX
                            [latitude] => 32.3361
                            [longitude] => -94.7363
                        )

                    [16] => Array
                        (
                            [name] => Monroe, VA
                            [latitude] => 37.4991
                            [longitude] => -79.1247
                        )

                    [17] => Array
                        (
                            [name] => Monroe, WA
                            [latitude] => 47.8524
                            [longitude] => -121.982
                        )

                    [18] => Array
                        (
                            [name] => Monroe, NC
                            [latitude] => 34.9826
                            [longitude] => -80.5489
                        )

                    [19] => Array
                        (
                            [name] => Monroe, WI
                            [latitude] => 42.603
                            [longitude] => -89.6451
                        )

                    [20] => Array
                        (
                            [name] => Monroe, MI
                            [latitude] => 41.9079
                            [longitude] => -83.4431
                        )

                    [21] => Array
                        (
                            [name] => Monroe, UT
                            [latitude] => 38.6311
                            [longitude] => -112.121
                        )

                    [22] => Array
                        (
                            [name] => Monroe, GA
                            [latitude] => 33.7954
                            [longitude] => -83.7133
                        )

                    [23] => Array
                        (
                            [name] => Monroe, IA
                            [latitude] => 41.522
                            [longitude] => -93.1059
                        )

                    [24] => Array
                        (
                            [name] => Monroe, NY
                            [latitude] => 41.3281
                            [longitude] => -74.1871
                        )

                    [25] => Array
                        (
                            [name] => Monroe Bridge, MA
                            [latitude] => 42.722
                            [longitude] => -72.9418
                        )

                    [26] => Array
                        (
                            [name] => Monroe, NJ
                            [latitude] => 40.3303
                            [longitude] => -74.4392
                        )

                )

        )

)


Comments

  • Posted 03/16/10 11:49:36 AM
    An extremely unique component. Kudos!

Comments are closed for articles over a year old