Darren Mothersele

Software Developer

Warning: You are viewing old, legacy content. Kept for posterity. Information is out of date. Code samples probably don't work. My opinions have probably changed. Browse at your own risk.

Facebook Graph API with Drupal Feeds

Oct 4, 2011

web-dev

There are several approaches to integrating Drupal with Facebook, the most active modules being Facebook Connect and Drupal for Facebook. I've been playing around with a slightly different approach that interacts with the Graph API using the Feeds and Rules modules. Read on for more details...

The first step is connecting to Facebook and linking a Facebook user with a Drupal user. This is handled quite nicely by the FB module, but could be implemented in another way if you feel the FB suite of modules adds too much bloat. You'll need to install the fb_user_app module as this is the module that gives you the access_token you will need to query the Graph API on behalf of a user. You will need to ensure your Facebook App requests the offline_access permission. If you don't have this permission you will find that the access tokens expire after a few minutes, with the offline_access extended permission the tokens don't expire. The access_token is stored in the fb_user_app table of the database (hence the need for the fb_user_app module) and for historical reasons it's stored in a column called "session_key"!

In order to make use of this you need to install the token module and define a couple of user tokens. One to access the user's Facebook ID, and another to get their access token. If you've not defined your own tokens in Drupal before take a look at the Token Starter module included in the Token package. Here's a code snippet that will help:

<?php
// declare a couple of Tokens:
function fb_user_tokens_token_list($type = 'all') {
 
$tokens = array();
  if (
$type == 'user') {
   
$tokens['user']['user-facebook-id'] = t("The Facebook user ID of the user.");
   
$tokens['user']['user-facebook-access-token'] = t("The Facebook access token of the user");
  }
  return
$tokens;
}

// Look up the values for the tokens:
function fb_user_tokens_token_values($type, $object = NULL, $options = array()) {
 
$values = array();
  if (
$type == 'user' && !empty($object)) {
   
$facebook_id = db_result(db_query("SELECT fbu FROM {fb_user} WHERE uid = %d", $object->uid));
    if (!empty(
$facebook_id)) {
     
$facebook_access_token = db_result(db_query("SELECT session_key FROM {fb_user_app} WHERE fbu = %d", $facebook_id));
    } else {
     
$facebook_access_token = '';
    }
   
$values['user-facebook-id'] = $facebook_id;
   
$values['user-facebook-access-token'] = $facebook_access_token;
  }
  return
$values;
}
?>

You then need to install and configure Feeds, in order to fetch content from the Graph API, parse it and then process it. The bit of this that I couldn't find a module for was fetching content from a tokenized URL. Use the Facebook Graph Explorer to see what URLs you need to hit to get the data you need. Also, check if you need any specific permissions. The URLs look something like this:

https://graph.facebook.com/[FB_ID]/friends?access_token=[ACCESS_TOKEN]

In order to construct the actual URL the two tokens defined previously are required. I created a simple Feeds fetcher plugin that allows you to use tokens in the URL. I would post this as a module, but it's no where near finished quality. Here is the class, it works, but it's not finished:

<?php
class FeedsTokenizedFetcher extends FeedsFetcher {
  public function
fetch(FeedsSource $source) {
   
$feed_node = node_load($source->feed_nid);
   
$account = user_load($feed_node->uid);
   
$url = token_replace_multiple($this->config['tokenized_url'], array('user' => $account));
   
$result = drupal_http_request($url);
    if (
$result->code == 200) {
      return new
FeedsImportBatch($result->data, $source->feed_nid);
    } else {
     
// oops... error!
     
return new FeedsImportBatch('', $source->feed_nid);
    }
  }
  public function
configDefaults() {
    return array(
'tokenized_url' => '');
  }
  public function
configForm(&$form_state) {
   
$form = array();
   
$form['tokenized_url'] = array(
     
'#type' => 'textarea',
     
'#title' => t('Tokenized URL'),
     
'#description' => t('The URL that data will be fetched from. All tokens will be replaced before the HTTP call is made.'),
     
'#default_value' => $this->config['tokenized_url'],
    );
   
$form['tokenized_help'] = array(
     
'#type' => 'markup',
     
'#value' => theme('token_help', 'user'),
    );
    return
$form;
  }
}
?>

So, use this as the fetcher plugin for Feeds, then grab the JSONpath parser plugin for Feeds and use that to parser the JSON object that is returned from the Graph API. You can then use any mapping plugin to process the result, for example the node mapper if you want to create a node (profile node?) from the result, or the data mapper would be a good idea if you're expecting to collect a lot of data (friends lists?).

I attached this Feed Importer configuration to a node, and set up a Rule to automatically create one of these every time a user registered on the site using Facebook. This nicely automates the whole process.

The next step is to look at using Rules to automate making POSTs to the Graph API. I'll be sure to blog again if I make any more progress with this methodology.