The PHP Recipe application is a small but complete example that demonstrates the five Google Base API services: queries, insertions, deletions, updates, and batch commands. This version uses the Zend Google Data Client Library to interact with the Google Base server, eliminating the need to manually construct and parse XML and HTTP interactions.
You can download the source code for the sample program and host it on your own web server. You will also need to download the Zend Google Data Client Library if you want to run a local copy of the demo. This sample is compatible with the 0.9.x series of Zend Google Data Client Library releases. You must be running PHP 5.1.4 or later in order to use this client library.
After installing the PHP sample application, ensure that the set_include_path call on line 4 points to the directory where you downloaded the Zend Google Data Client Library.
When you first use the Recipe application, you will have to log in to your Google Account and grant the script permission to access your Google Base entries.
The Recipe application allows users to upload new recipes to Google Base, edit or delete recipes they have already added, or delete all their recipes with a batch request. It uses GET and POST parameters to maintain two key elements of program state: the user's AuthSub token and requested action (insert, update, delete, or batch).
This section describes how the Recipe application initially interacts with the user and obtains a session token from the AuthSub server.
Note: Zend removed the setDeveloperKey() method in the 0.9 release of the client library. Therefore, this example does not illustrate how to handle the developer token. Please note that although Google Base does not currently enforce the usage of developer keys, the Terms of Use requires their inclusion. Google reserves the right to enforce this provision at any time.
showIntroPage()When a user first arrives at the Recipe application, no GET or POST parameters are provided to the form. This indicates that the user has not yet obtained a single-session token. The code below uses the Zend_Gdata_AuthSub::getAuthSubTokenUri method to set up a link to the AuthSubRequest page. It passes these values as arguments:
$next_url, corresponding to the next AuthSubRequest parameter, indicates that the user should be returned to the Recipe application after obtaining a token;$itemsFeedURL, corresponding to the scope AuthSubRequest parameter, indicates that the Recipe application will only access the items feed;0, corresponding to the secure AuthSubRequest parameter, indicates a request for a non-secure token (since this is not a registered application);1, corresponding to the session AuthSubRequest parameter, indicates a request for a token that can be exchanged for a multi-use (session) token.
function showIntroPage() {
global $itemsFeedURL;
$next_url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$redirect_url = Zend_Gdata_AuthSub::getAuthSubTokenUri($next_url, $itemsFeedURL, 0, 1);
...
}
The remainder of showIntroPage (omitted for brevity) prints the HTML tags to create a table containing this link.
exchangeToken()After the user authenticates to his Google Account using AuthSub, he is redirected back to the Recipe application page (as a result of the next parameter to AuthSubRequest). The redirection URL will contain one GET parameter: the single-use token granted by AuthSub.
The exchangeToken() function below is used to exchange the user's single-use token for a multi-use (session) token. The resulting session token is used for all interaction with the Google Base API: queries, insertions, deletions, updates, and batch commands. exchangeToken() simply calls the Zend_Gdata_AuthSub::getAuthSubSessionToken method provided in the Zend client library:
function exchangeToken($token) {
return Zend_Gdata_AuthSub::getAuthSubSessionToken($token);
}
This section describes how the Recipe application builds XML requests to be sent to the Google Base feed for item creation, edits, and batch deletions.
buildNewEntry()The buildNewEntry() function is used to construct the XML document that is sent when the user inserts a new recipe. It uses the helper function createOrEditEntry, which formats the POST fields submitted by the user (recipe_title, cuisine, and so forth) into a Zend_Feed_EntryAtom object :
function createOrEditEntry($entry) {
$newEntry = $entry;
$newEntry->category['scheme'] = 'http://base.google.com/categories/itemtypes';
$newEntry->category['term'] = 'Recipes';
$newEntry->title['type'] = 'text';
$newEntry->title = $_POST['recipe_title'];
$newEntry->{'g:cuisine'} = $_POST['cuisine'];
$newEntry->{'g:item_type'} = 'Recipes';
$newEntry->{'g:item_type'}['type'] = 'text';
$newEntry->{'g:cooking_time'} = $_POST['time_val'] . ' ' .
$_POST['time_units'];
$newEntry->{'g:cooking_time'}['type'] = 'intUnit';
$newEntry->{'g:main_ingredient'} = $_POST['main_ingredient'];
$newEntry->{'g:main_ingredient'}['type'] = 'text';
$newEntry->{'g:serving_count'} = $_POST['serves'];
$newEntry->{'g:serving_count'}['type'] = 'number';
$newEntry->content = $_POST['recipe_text'];
return $newEntry;
}
buildNewEntry() then calls this function with a new Zend_Feed_EntryAtom object:
function buildNewEntry() {
return createOrEditEntry(new Zend_Feed_EntryAtom());
}
buildUpdatedEntry()The buildUpdatedEntry() function is used to construct the XML document that is sent when the user updates an existing recipe. It also leverages the createOrEditEntry helper function, but it passes an existing Zend_Feed_EntryAtom object instead of a new one:
function buildUpdatedEntry($entry) {
return createOrEditEntry($entry);
}
buildBatchXML()The buildBatchXML() function creates the XML document used to perform a batch deletion request. It formats the links to each item's feed URI (submitted as POST fields when the user clicks the Delete All button) into a Zend_Feed_EntryAtom object using the Atom format for batch processing.
function buildBatchXML() {
$counter = 0;
$result = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$result .= '<feed xmlns="http://www.w3.org/2005/Atom"' . "\n";
$result .= ' xmlns:g="http://base.google.com/ns/1.0"' . "\n";
$result .= ' xmlns:batch="http://schemas.google.com/gdata/batch">' . "\n";
foreach($_POST as $key => $value) {
if (substr($key, 0, 5) == "link_") {
$counter++;
$newEntry = new Zend_Feed_EntryAtom();
$newEntry->{'id'} = $value;
$newEntry->{'batch:operation'}['type'] = 'delete';
$newEntry->{'batch:id'} = $counter;
$result .= $newEntry->saveXMLFragment();
}
}
$result .= '</feed>' . "\n";
return $result;
}
This section describes how the Recipe application interacts with the Google Base feed to retrieve, insert, update, and delete items.
The code below, called by showRecipeListPane to create the array of user-entered recipes, uses the Zend_Gdata_AuthSub::getHttpClient method to create an HTTP client with the user's authentication token. It then creates a Zend_Gdata object , wrapped around this client, and calls getFeed to retrieve the user's items feed. Since getFeed throws an Exception if the feed retrieval fails, the operation is wrapped in a try-catch block:
global $itemsFeedURL;
$client = Zend_Gdata_AuthSub::getHttpClient($token);
$gdata = new Zend_Gdata($client);
try {
$feed = $gdata->getFeed($itemsFeedURL . "?");
...
} catch (Exception $e) {
...
}
The individual entries in the feed can then be accessed with a foreach loop; the entries' properties can be accessed with functions of the same names, as follows:
foreach ($feed as $feed_entry) {
$link_list = $feed_entry->link();
$href = $link_list[0]->getAttribute('href');
print "<tr>\n";
print '<td align="left" valign="top"><b><a href="' . $href . '">' .
$feed_entry->title() . '</a></b></td>' . "\n";
print '<td style="text-align:center;vertical-align:top">' .
$feed_entry->cuisine() . '</td>' . "\n";
print '<td style="text-align:center;vertical-align:top">' .
$feed_entry->serving_count() . '</td>' . "\n";
...
}
postItem()The postItem() function inserts a new recipe by performing an HTTP POST on the user's items feed. It uses the Zend_Gdata::post method to transmit the XML content of the new entry (created in buildNewEntry(), above).
function postItem() {
global $itemsFeedURL;
$client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
$gdata = new Zend_Gdata($client);
$response = $gdata->post(buildNewEntry()->saveXML(), $itemsFeedURL);
return $response;
}
updateItem()The updateItem function updates an existing recipe by performing an HTTP PUT on that recipe's feed URI. It finds the entry in the user's items feed, then uses the Zend_Feed_EntryAtom::save method to transmit the XML content of the updated entry (created in buildUpdatedEntry(), above).
function updateItem() {
global $itemsFeedURL;
$client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
$gdata = new Zend_Gdata($client);
$feed = $gdata->getFeed($itemsFeedURL . "?");
foreach ($feed as $feed_entry) {
if ($feed_entry->link('edit') == $_POST['link']) {
$updatedEntry = buildUpdatedEntry($feed_entry);
$updatedEntry->save();
return true;
}
}
}
deleteItem()The deleteItem() function deletes a recipe the user has entered previously by performing an HTTP DELETE on its feed URI. It uses the Zend_Gdata::delete method to transmit this request.
function deleteItem() {
$client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
$gdata = new Zend_Gdata($client);
$gdata->delete($_POST['link']);
}
batchDelete()The batchDelete() function deletes all of the user's recipes by issuing a batch request to the Google Base API. This is accomplished by performing an HTTP POST to the batch feed URL, specifying the batch XML document as POST data.
function batchDelete() {
global $itemsFeedURL;
$client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
$gdata = new Zend_Gdata($client);
$response = $gdata->post(buildBatchXML(), $itemsFeedURL . "/batch");
return $response;
}
Can't get the PHP sample code to work on your server? Here are a few suggestions:
set_include_path call points to the directory where you downloaded the Zend Google Data Client Library.