My favorites | English | Sign in

Google Base Data API (Labs)

Sample Applications: PHP 5 (Zend Framework)

The PHP sample application is a small but complete example of creating a Recipe application using the Google Base API. It 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 (except with batch operations) and HTTP interactions.

For a full run-down of the Google Base functionality included in the Zend PHP Client Library's, see the PHP Developers' Guide. New

Contents

  1. Installing the Recipe application
  2. Stepping through the code
    1. Setup and token exchange
      1. Building the introductory page
      2. Exchanging the single-session token
    2. Retrieving the user's entries
    3. Managing Recipes
      1. Insert a new Recipe
      2. Update an existing Recipe
      3. Delete a single Recipe
      4. Batch delete many Recipes
  3. Troubleshooting

Installing the Recipe application

Download the full source code

Note: You will need to download the Zend Google Data Client Library before using this application. The sample is compatible with the 1.5.x series of Zend Google Data Client Library releases. You also must be running PHP 5.1.4 or later in order to use the client library.

After installing the PHP sample application, ensure that the require_once 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.

Stepping through the code

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). You could also use $_SESSION variables to store the session token.

Setup and token exchange

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 key. 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.

Building the introductory page: 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;
  • $scope, corresponding to the scope AuthSubRequest parameter, indicates that the Recipe application will only access the items feed;
  • $secure, corresponding to the secure AuthSubRequest parameter, 0 indicates a request for a non-secure token (since this is not a registered application);
  • $session, corresponding to the session AuthSubRequest parameter, 1 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'];
  $scope = $itemsFeedURL;
  $secure = 0;
  $session = 1;
  $redirect_url = Zend_Gdata_AuthSub::getAuthSubTokenUri($next_url, $scope, $secure, $session);
  
  ...
}

The remainder of showIntroPage (omitted for brevity) prints the HTML tags to create a table containing this link.

Exchanging the single-session token: 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:

Retrieving the user's entries: showRecipeListPane()

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 getGbaseItemFeed object with the url of the items feed (global $itemsFeedURL) as its parameter. Since getGbaseItemFeed throws an Zend_Gdata_App_Exception if the feed retrieval fails, the operation is wrapped in a try-catch block:

function showRecipeListPane($token) {
  global $itemsFeedURL;
  
  $client = Zend_Gdata_AuthSub::getHttpClient($token);
  $gdata = new Zend_Gdata_Gbase($client);
  
  global $itemsFeedURL;
    
    $client = Zend_Gdata_AuthSub::getHttpClient($token);
    $gdata = new Zend_Gdata_Gbase($client);
    try {
    $feed = $gdata->getGbaseItemFeed($itemsFeedURL . '/-/testrecipes');
   
    print '<td style="width:50%;text-align:center;vertical-align:top">' . "\n" .
          '<a href="http://www.google.com/base/dashboard" target="_blank">' . 
          'View all of your published items</a>' . 
          '<table>' . "\n" . 
          '<tr><th colspan="5" style="text-align:center">' . 
          'Recipes you have added that searchable via the API</th></tr>' . "\n";
      
      ...
      
    } catch (Zend_Gdata_App_Exception $e) {
      showMainMenu("Error: " . $e->getMessage(), $token);
    }
}

The individual entries in the feed are accessed with a foreach loop; the entries' properties can be accessed by name, as follows:

...

foreach ($feed->entries as $feed_entry) {    
  $href = $feed_entry->link[0]->href;
  $title = $feed_entry->title->text;
  $id = $feed_entry->id->text;
  
  $baseAttributeArr = $feed_entry->getGbaseAttribute('cuisine');
  // Only want first cuisine
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $cuisine = $baseAttributeArr[0]->text;
  } 
  
  $baseAttributeArr = $feed_entry->getGbaseAttribute('serving_count');
  // Only want first serving_count
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $serving_count = $baseAttributeArr[0]->text;
  } 

  print "<tr>\n";
        '<td align="left" valign="top"><b><a href="' . $href . '">' . $title . '</a></b></td>' . "\n";
        '<td style="text-align:center;vertical-align:top">' . $cuisine . '</td>' . "\n";
        '<td style="text-align:center;vertical-align:top">' . $serving_count . '</td>' . "\n";
}

...

Managing Recipes

Inserting a new Recipe: postItem()

The postItem() function inserts a new recipe by performing an HTTP POST on the user's items feed. It uses the Zend_Gdata_Gbase::insertGbaseItem method to transmit the content of the new entry (created using newItemEntry) to Google Base. Base-specific attributes are added using addGbaseAttribute.

Note: Items that are inserted using this sample application will not show up in your list of Recipes right away. The default publishing_priority is set to low. However, you can immediately verify that an item was inserted by checking your Google Base Dashboard.

function postItem($dryRun = false) { 
  $client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
  $gdata = new Zend_Gdata_Gbase($client);

  $newEntry = $gdata->newItemEntry();
  
  // Add title
  $newEntry->title = $gdata->newTitle(trim($_POST['recipe_title']));

  // Add some content
  $newEntry->content = $gdata->newContent($_POST['recipe_text']);
  $newEntry->content->type = 'text';

  // Define item type
  $newEntry->itemType = 'testrecipes';
  $newEntry->itemType->type = 'text';

  // Add item-specific attributes
  $newEntry->addGbaseAttribute('cuisine', $_POST['cuisine'], 'text');
  $newEntry->addGbaseAttribute('cooking_time', $_POST['time_val'] . ' ' . $_POST['time_units'], 'intUnit');
  $newEntry->addGbaseAttribute('main_ingredient', $_POST['main_ingredient'], 'text');
  $newEntry->addGbaseAttribute('serving_count', $_POST['serves'], 'number');

  // Post the item
  $createdEntry = $gdata->insertGbaseItem($newEntry, $dryRun);

  return $createdEntry;
}

Call this method with $dryRun=true if you want to test the insert operation without actually posting the Recipe.

Updating an existing Recipe: updateItem()

The updateItem() function is used to construct the XML document that is sent when the user updates an existing recipe. It leverages several of the the library's Base-specific methods such as getGbaseItemEntry, to retrieve the item entry to edit:

function updateItem() { 
  $client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
  $gdata = new Zend_Gdata_Gbase($client);
  
  $itemUrl = $_POST['link'];
  $updatedEntry = $gdata->getGbaseItemEntry($itemUrl);
  
  // Update title
  $updatedEntry->title = $gdata->newTitle(trim($_POST['recipe_title']));

  // Update content
  $updatedEntry->content = $gdata->newContent($_POST['recipe_text']);
  $updatedEntry->content->type = 'text';

  // Update item-specific attributes
  $baseAttributeArr = $updatedEntry->getGbaseAttribute('cuisine');
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $baseAttributeArr[0]->text = $_POST['cuisine'];
  }
  
  $baseAttributeArr = $updatedEntry->getGbaseAttribute('cooking_time');
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $baseAttributeArr[0]->text = $_POST['time_val'] . ' ' . $_POST['time_units'];
  }
  
  $baseAttributeArr = $updatedEntry->getGbaseAttribute('main_ingredient');
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $baseAttributeArr[0]->text = $_POST['main_ingredient'];
  }
  
  $baseAttributeArr = $updatedEntry->getGbaseAttribute('serving_count');
  if (isset($baseAttributeArr[0]) && is_object($baseAttributeArr[0])) {
    $baseAttributeArr[0]->text = $_POST['serves'];
  }

  $updatedEntry = $gdata->updateGbaseItem($updatedEntry, false); 
  
  return $updatedEntry;
}

Deleting a single Recipe: deleteItem()

The deleteItem() function delete a user's Recipe by using deleteGbaseItem.

function deleteItem() {
  $client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
  $gdata = new Zend_Gdata_Gbase($client);

  $itemUrl = $_POST['link'];
  $deleteEntry = $gdata->getGbaseItemEntry($itemUrl);
  
  $dryRun = false;
  $gdata->deleteGbaseItem($deleteEntry, $dryRun);
}

Batch delete many Recipes: 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 using the Zend_Gdata_Gbase::post method. The first argument is the the batch feed URL, and the second argument is the XML POST data (built by the helper function buildBatchXML).

Note: It is more efficient to use this batch method to delete multiple items rather than calling deleteItem() many times.

function buildBatchXML() {
  $result =  '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . 
             '<feed xmlns="http://www.w3.org/2005/Atom"' . "\n" . 
             ' xmlns:g="http://base.google.com/ns/1.0"' . "\n" . 
             ' xmlns:batch="http://schemas.google.com/gdata/batch">' . "\n";
  
  $counter = 0;
  foreach($_POST as $key => $value) {
    if(substr($key, 0, 5) == "link_") {
      $counter++;

      $result .= '<entry>' . "\n" . 
                 '<id>' . $value . '' . "\n" . 
                 '<batch:operation type="delete"/>' . "\n" . 
                 '<batch:id>' . $counter . '</batch:id>' . "\n" . 
                 '</entry>' . "\n";
    }
  }
  $result .= '</feed>' . "\n";

  return $result;
}
function batchDelete() {
  global $itemsFeedURL;
        
  $client = Zend_Gdata_AuthSub::getHttpClient($_POST['token']);
  $gdata = new Zend_Gdata_Gbase($client);
  
  $response = $gdata->post(buildBatchXML(), $itemsFeedURL . '/batch');
  
  return $response;
}

You can find more information on batch requests here.

Troubleshooting

Can't get the PHP sample code to work on your server? Here are a few suggestions: