sfYahooGeocoderPlugin ===================== Introduction ------------ This plugin provides an easy way to call the Yahoo! Maps Geocoding service in order to retrieve geographical data according to an address, zip code, state or country. This service is provided by Yahoo! and returns, in php or xml formats, latitude and longitude of a geographical place in the world. The sfYahooGeocoderPlugin abstracts the Yahoo! API thanks to a clear, simple and flexible PHP API. Note that you will have to suscribe to the service to obtain your own Yahoo! API Key. Features --------- * Call the Yahoo! Maps Geocoding service and get latitude and longitude informations, * Custom HTTP adapter (CURL or Stream) to call the webservice * Extensible, response objects are instance of the sfYahooGeocoderResponse * Chaining methods Installation ------------ * go to your project's root * Install the plugin: ./symfony plugin:install sfYahooGeocoderPlugin * clear cache: ./symfony cc Usage ----- ### The sfYahooGeocoder API ### The `sfYahooGeocoder` object is the main component of the plugin. It provides the API to call the Yahoo! Maps Geocoder webservice and obtain the geographical informations stored in a response object. This object is composed of the following methods : * `string getApiKey()` : returns the Yahoo! API Key, `appid` parameter, * `string getStreet()` : returns the `street` parameter, * `string getCity()` : returns the `city` parameter, * `string getZipCode()` : returns the `zip` code parameter, * `string getState()` : returns the `state` parameter, * `string getLocation()` : returns the `location` parameter, * `string getOutput()` : returns the `output` parameter, * `string getRawResponse()` : returns the raw http response (as php or xml), * `sfYahooAdapterHttp getHttpAdapter()` : returns the current http adapter, * `setHttpAdapter(sfYahooAdapterHttp $httpAdapter)` : changes the http adapter which calls the webservice, * `setStreet(string $street)` : sets the street to locate, * `setCity(string $city)` : sets the city to locate, * `setZipCode(string $zipCode)` : sets the zip code to locate, * `setState(string $state)` : sets the state to locate, * `setLocation(string $location)` : sets a location string, for example : `Champs Elysées, Paris, France`, * `setOutput(string $output)` : sets the Yahoo! expected response output, `xml` or `php`, * `sfYahooGeocoderResponseCollection geocode()` : calls the webservice and returns an instance of `sfYahooGeocoderResponseCollection` class, which contains one or more `sfYahooGeocoderResponse` objects, All `setFooBar()` methods return the current object, which allows to chain methods as it will be explained later. ### Usage examples ### The simpliest usage example is given below : [php] <?php $yahooGeocoder = new sfYahooGeocoder('YOUR_API_KEY'); try { $geoResponse = $yahooGeocoder->setLocation('Champs Elysées, Paris, France')->geocode(); echo $geoResponse->getLatitude(); echo $geoResponse->getLongitude(); } catch (Exception $e) { throw new Exception('An error occured !'); } As you can see, the API allows to chain methods to gain in readability. A more complex example is shown below : [php] <?php $yahooGeocoder = new sfYahooGeocoder('YOUR_API_KEY'); try { $geoResponse = $yahooGeocoder-> setStreet('42 Avenue des Champs Elysées')-> setState('France')-> setCity('Paris')-> setZipCode('75008')-> geocode(); echo $geoResponse->getLatitude(); echo $geoResponse->getLongitude(); } catch (Exception $e) { throw new Exception('An error occured !'); } The `geocode()` method returns an object containing a collection of objects representing geographical data. Its API is described in the following part. ### The `sfYahooGeocoderResponseCollection` API ### The `geocode()` method returns a `sfYahooGeocoderResponseCollection` object, which contains a collection of `sfYahooGeocoderResponsePhp` or `sfYahooGeocoderResponseXml` objects. Below is the API of this object. * `mixed __call()` : calls an accessor method of the current `sfYahooGeocoderResponse` object of the collection, * `int count()` : returns the number of `sfYahooGeocoderResponse` objects in the collection, * `sfYahooGeocoderResponse getByIndex($index)` : returns a `sfYahooGeocoderResponse` object located at position `$index`, * `boolean isEmpty()` : returns wether or not the collection is empty, * `array toArray()` : returns the array representation of the collection, * `sfYahooGeocoderResponse getFirst()` : returns the first object of the collection, * `sfYahooGeocoderResponse getLast()` : returns the last object of the collection, * `boolean clear()` : empties the collection, * `array getObjects()` : returns all the collection's objects in an array, ### The `sfYahooGeocoderResponse` API ### The API of derived `sfYahooGeocoderResponse` objects is described below. * `boolean hasCoordinates()` : returns wether or not the latitude and longitude are set, * `array toArray()` : returns the array representation of geographical data, * `double getLatitude()` : returns the latitude as a double, * `double getLongitude()` : returns the longitude as a double, * `string getCity()` : returns the city, * `string getZip()` : returns the zip code, * `string getState()` : returns the state, * `string getCountry()` : returns the country code, * `string getAddress()` : returns the address, * `string getPrecisionLevel()` : returns the precision level, ### ArrayAccess implementation for response objects ### The `sfYahooGeocoderResponse` class implements the `ArrayAccess` interface of the PHP SPL. So, every information accessible by an explicit accessor can be get via an array access interface : [php] <?php $yahooGeocoder = new sfYahooGeocoder('YOUR_API_KEY'); try { $geoResponse = $yahooGeocoder-> setStreet('42 Avenue des Champs Elysées')-> setState('France')-> setCity('Paris')-> setZipCode('75008')-> geocode(); echo $geoResponse['Latitude']; echo $geoResponse['Longitude']; echo $geoResponse['City']; echo $geoResponse['State']; echo $geoResponse['Country']; echo $geoResponse['Zip']; echo $geoResponse['Address']; echo $geoResponse['PrecisionLevel']; echo $geoResponse['Content']; } catch (Exception $e) { throw new Exception('An error occured !'); } The HTTP adapter ---------------- The GET request is managed through an HTTP adapter, which calls the webservice and gets the string response. The plugin is bundled with 2 default http adapters : * `sfYahooAdapterHttpStream` (default) : uses the `stream_context_create()` and `file_get_contents()` php functions, * `sfYahooAdapterHttpCurl` : uses the `CURL` API Suppose that the `stream_context_create()` function is not installed on the php configuration, you can try to call the webservice via the CURL library by changing the default http adapter : [php] <?php $yahooGeocoder = new sfYahooGeocoder('YOUR_API_KEY'); try { $geoResponse = $yahooGeocoder-> setHttpAdapter(new sfYahooAdapterHttpCurl())-> setStreet('42 Avenue des Champs Elysées')-> setState('France')-> setCity('Paris')-> setZipCode('75008')-> geocode(); } catch (Exception $e) { throw new Exception('An error occured !'); } Create your own HTTP Adapter ---------------------------- If you need to use a different way to call the webservice, you can create your own HTTP Adapter class that inherits from the abstract `sfYahooAdapterHttp` class. You will have to implement the abstract protected method `doSend()` that makes the call to the webservice, and then returns the string response : [php] <?php class myYahooAdapterHttp extends sfYahooAdapterHttp { protected function doSend() { $content = ''; // Call the webservice and returns the response content return $content; } } Concret example of usage ------------------------- Suppose we are managing a contacts list. Each contact has its personal address (`street`, `zip code`, `city` and `state`) and we want to locate it on a Yahoo! Maps. So, we need the contact's location to be stored in the database to avoid to call the Yahoo! service every time we need to point the address on a map. The aim is to save the `latitude` and `longitude` values in the `contact_user` table. The better way to achieve is to use the `sfYahooGeocoder` object into the `save()` method of the contact object : [php] <?php class ContactUser extends BaseContactUser { public function save(Doctrine_Connection $con) { if ($this->isNew()) { $this->setLocation(); } return parent::save($con); } public function setLocation() { try { $yahooGeocoder = new sfYahooGeocoder('YOUR_API_KEY'); $geoResponse = $yahooGeocoder-> setState($this->getState())-> setCity($this->getCity())-> setZipCode($this->getZipCode())-> setStreet($this->getStreet())-> geocode(); if (!$geoResponse->isEmpty()) { $this->setLatitude($geoResponse->getLatitude()); $this->setLongitude($geoResponse->getLongitude()); } } catch (Exception $e) { } } } Unit testing ------------ The plugin has been unit tested to provide a robust API : * run the tests: $ php plugins/sfYahooGeocoderPlugin/test/unit/geocoder/sfYahooGeocoderTest.php $ php plugins/sfYahooGeocoderPlugin/test/unit/parser/sfYahooGeocoderParserPhpTest.php $ php plugins/sfYahooGeocoderPlugin/test/unit/parser/sfYahooGeocoderParserXmlTest.php $ php plugins/sfYahooGeocoderPlugin/test/unit/response/sfYahooGeocoderResponsePhpTest.php $ php plugins/sfYahooGeocoderPlugin/test/unit/response/sfYahooGeocoderResponseXmlTest.php $ php plugins/sfYahooGeocoderPlugin/test/unit/response/sfYahooGeocoderResponseCollectionTest.php TODO ---- * Add a task to run the unit test suites * Add a response cache manager to cache XML and PHP response in a storage space (disk, database, memory...) License and credits ------------------- See `LICENSE` file.