Phase 5: changing the flights pages to Google Maps with JSON/AJAX
Setting up the flights data with one page per airport created an over-large number of pages and was in general very inefficient so, as I was considering replacing the SVG map with a Google Map anyway, I decided to go the whole hog and incorporate all the route pages into that. Google Maps is of course largely about Javascript, which is not the subject of this tutorial, but the map still needs to get the data from the server, and the simplest way to do that is for the requests to the server to generate files in JSON format. I suppose you could just have PHP scripts which bypass Symfony completely, but here's how I did this using Symfony actions.
I set the map up so that initially it shows the main air/ports, i.e. those in England I track in the DB. People can then click on a marker, and this displays the routes from that air/port. There are thus three calls to the server, the initial display and lists for the appropriate airport and seaport, and hence three Symfony actions.
Routing
ports_json:
url: /flights/ports2json.
param: { module: flights, action: ports2json }
routes_json:
url: /flights/flights2json/:from.
param: { module: flights, action: flights2json }
ferries_json:
url: /flights/ferries2json/:from.
param: { module: flights, action: ferries2json }
Note that the urls end with '.', i.e. there is no .html suffixActions
public function executeFerries2json()
{
$from = $this->getRequestParameter('from');
$con = Propel::getConnection('flights');
$stmt = $con->prepare("SELECT 'ferries' as datatype, toport as port, latitude, longitude, ferries.co as co, ferrycos.name as coname, web, comments FROM ferries, ports, ferrycos WHERE toport = ports.name and ferries.co = ferrycos.co and fromport = ? union SELECT 'ferries' as datatype, fromport as port, latitude, longitude, ferries.co as co, ferrycos.name as coname, web, comments FROM ferries, ports, ferrycos WHERE fromport = ports.name and ferries.co = ferrycos.co and toport = ? ORDER BY port, coname ASC");
$stmt->bindValue(1, $from);
$stmt->bindValue(2, $from);
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$rows[] = $row;
}
$this->getResponse()->setContent("loadFerries(".json_encode($rows).")");
return sfView::NONE;
}
Here, we use Propel's connection logic, but then use one of PDO's prepared statements to execute the query. The result is then JSON-encoded, wrapped in the call of the loadFerries() Javascript method, and put directly in the Content property of the Response object. As there is no view involved, we return 'sfView::NONE'. So, the Javascript routine in the client calls, for example, '/flights/ferries2json/Dover' on the server, which gets a list of the appropriate to-ports from the database. These are returned to the client as a Javascript array, wrapped in loadFerries(). The client runs loadFerries(), which creates the markers and puts them in the appropriate places on the map.
