Tuesday, September 4, 2007

Whip Up a Yahoo! Mashup Using PHP Part III

LocalSearch Client Class in PHP 5

Now let's extend the YahooAPI class to query the Yahoo! Local Search API. We can easily create a class that manages all this work for us. Instead of the previous procedural code, if we extend the YahooAPI class and create some appropriately-named methods -- for example locationSearch($query, $location) -- we can further simplify the process of interacting with the APIs.

I've written an example class that generally covers everything we need for interacting with the Local Search API. It has three main methods: locationSearch, positionSearch and extractResults. Here's the code:

The constructor method sets the basic properties we'll always need for each Local Search API request:

public function __construct()
{
$this->setParam('output','php');
$this->setService('http://local.yahooapis.com/'.
'LocalSearchService/V3/localSearch');
$this->setAppID('your-app-id-here');
}

The two search methods represent different ways of performing a search, depending on whether or not we have a location name or exact GPS coordinates. They simply set the required parameters and call the doAPICall method of the parent YahooAPI class:

public function locationSearch($query,$in_location)
{
$this->setParam('query',$query);
$this->setParam('location',$in_location);
return $this->doAPICall();
}

public function positionSearch($lat,$long)
{
$this->setParam('query','*');
$this->setParam('latitude',$lat);
$this->setParam('longitude',$long);
return $this->doAPICall();
}


The extractResults method saves us entering ['ResultSet']['Result'] all the time when we want to output the results, because the data we need will always be within that part of the returned array:

public function extractResults()
{
$return = $this->getResults();
$return = $return['ResultSet']['Result'];
return $return;
}
}
?>

You'll find a copy of the code in the archive for the article. Keep it handy because we'll be using it in our example mashup. We'll also build a similar class for the Maps API later, as it has some slightly different requirements.

Our example "pizza" search, executed using our new LocalSearch class, now looks like this:

require_once('localsearch.class.php');

$localSearch = new LocalSearch();
$localSearch->locationSearch('Pizza','Palo Alto, CA');
$output = $localSearch->extractResults();

That's much easier, don't you think?

Yahoo! Maps AJAX API

Perform a quick web search and you could find the web sites for these pizza places, each of which would list the restaurant's address. But why would you go to all that trouble when Yahoo! provides all this data in the returned array -- as well as latitude and longitude information? Here's an example of the data returned:

[Title] => Patxi's Chicago Pizza
[Address] => 441 Emerson St
[City] => Palo Alto
[State] => CA
[Phone] => (650) 473-9999
[Latitude] => 37.445265
[Longitude] => -122.163432

Now that we have the location information, we need to figure out how to plot it on a map. Yahoo! provides a map image API, offering raw images of maps in PNG format, and (in theory) we could use GD to draw markers on the map. However, since we're building a web application, we can instead use the Maps AJAX API to generate a UI-friendly, interactive Yahoo! maps display. We can then add markers to the map in preset positions, using the bundled functions. (Note that the Maps AJAX API isn't really an Ajax API! In fact, there isn't any real Ajax at all -- that is, there are no XMLHttpRequest calls -- but due to the fact that the term Ajax has come to represent any web page technology that uses JavaScript and doesn't need to reload the web page to update itself, Ajax would be the best way to describe it.)

Unlike the other Yahoo! APIs, the Maps AJAX API isn't a REST-based web service. Instead, you have to include a JavaScript file on your page, create an instance of the map in a container on the page (usually a

) and manipulate it through JavaScript calls. Luckily, the HTML and JavaScript required are quite simple. Take a look at the mapoutput.php example in the code archive. This is all the JavaScript you'll need to generate the map:

var ymap = new YMap(document.getElementById('mC'),YAHOO_MAP_REG);
var mPoint = new YGeoPoint(37.4041960114344,-122.008194923401);
ymap.drawZoomAndCenter(mPoint, 3);
var marker = new YMarker(mPoint);
marker.addLabel('A');
marker.addAutoExpand('

Some Text
');
ymap.addOverlay(marker);

The first line creates a new instance of the YMap class, and assigns it to the element on the page with an ID of 'mC'. The second argument represents the desired map type, in this case a regular map rather than satellite imagery, YAHOO_MAP_SAT, or a hybrid of the two, YAHOO_MAP_HYB. The second line creates a YGeoPoint object, a point on the map based on latitude and longitude coordinates, while the third line calls the map object and tells it to centre itself on this new point and display the map, at a zoom level of 3.

The final three lines of JavaScript create a YMarker object, a visual map marker that expands to reveal some extra content when it's moused over. Our challenge is to generate all this with PHP, and to make the job easy, we're going to build a class that generates all the code for us.

Mashup Time!

Now that we've sorted out how to query the APIs and deal with the data, it's mashup time! As I mentioned before, we'll create a simple application that finds places with the local search API and, using the latitude and longitude coordinates from the returned search data, marks the exact locations of these places on a map from the maps API. And of course we'll wrap all the functionality up in a simple PHP class. The AJAX map API uses JavaScript code, so we'll use our PHP class to generate the required JavaScript based on the returned search data.

First, we'll start by querying the Maps API. I'll use the client class for the local search API, which I demonstrated earlier, to execute this sample query: 'Pizza' in 'Palo Alto, CA'. We need an instance of the LocalSearch class, and we'll use its locationSearch method to execute the API query. The extractResults method will give us the data that we want to work with. Now that we've built our client classes, all this can be achieved in three lines of code:

$localSearch = new LocalSearch();
$localSearch->locationSearch('Pizza','Palo Alto, CA');
$apiOutput = $localSearch->extractResults();

Let's take a step back for a moment and call print_r($apiOutput) to see what we have. The array $apiOutput now contains a number of sub-arrays, each of which is a single search result and contains (among other things) a 'Title', 'Latitude' and 'Longitude'. That's all we need for the moment, so let's quickly extract this information and delete the rest:

foreach($apiOutput as $id => $result)
{
$points[$id] = array($result['Title'],
$result['Latitude'],
$result['Longitude']);
}

Here are some sample values from our newly defined $points array:

[0] => Array
(
[0] => Patxi's Chicago Pizza
[1] => 37.445265
[2] => -122.163432
)

[1] => Array
(
[0] => Papa Murphys Pizza Take & Bake
[1] => 37.433243
[2] => -122.129291
)

For each marker we want to put on our map, we need to know its position, and we need some summary text that we can have appear when the user mouses over it. In this case, when visitors mouse over one of our markers, we'll show them the name of the place.

Now that we have all our locality information, we come to the tricky bit -- generating the map HTML and JavaScript. Basically, our map code consists of two distinct sections -- the HTML and CSS (for the map container), and the HTML and JavaScript. The includes the container

for the map and some JavaScript for the Maps AJAX API. For each marker we want to add to the map, we need a JavaScript YGeoPoint object to define its position, and a YMarker object to be the marker itself. We then customise the marker through the addLabel and addAutoExpand methods (many more are documented here) before placing it on the map using the map object's addOverlay method. We'll now create a PHP class that takes care of generating all of this JavaScript code, and call it AjaxMap.

Here's a summary of the methods our class will have:

  • getHeadHTML for generating code
  • getMapScript for generating code
  • initMarker for generating code for each marker

We'll also add some helper methods for customising the map:

  • setMapType for choosing between maps, satellite images, and hybrids
  • setMapContainer for setting the ID of the map container
  • addMarker for adding markers to the map

No comments:

About Me

Ordinary People that spend much time in the box
Powered By Blogger