Designing my first app against the Graph API, using version 2.1.2 of the Facebook supplied PHP library. Trying to maximize performance, etc out of the box and want to batch
I have given example for batch calls of fql queries. It might help someone.
//$current_user=facebook id
$query1="SELECT uid, name FROM user WHERE is_app_user=1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $current_user)";
$query2="SELECT uid, name, work_history FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = $current_user )";
$query3="SELECT uid, name, work, education FROM user WHERE uid = $current_user";
$queries = array(
array('method'=>'GET', 'relative_url'=>'method/fql.query?query='.str_replace(' ','+',$query1)),
array('method'=>'GET', 'relative_url'=>'method/fql.query?query='.str_replace(' ','+',$query2)),
array('method'=>'GET', 'relative_url'=>'method/fql.query?query='.str_replace(' ','+',$query3))
);
$objs = $facebook->api('/?batch='.json_encode($queries), 'POST');
$objs gets json array of whole result of thre queries.
And it is saving time a lot. This 3 queries individually takes total 9 seconds. With multiquery it takes 7 seconds. And with batch request it takes 3.6 seconds.
For Batch API, you could use the Facebook Batch PHP class.
Here is the code you would use:
<?php
// Facebook Batch Requests PHP Class
// by Gokhan Ozturk <gokhanozturk at gmail dot com> @ Nov 17, 2011
// Original Article: http://blog.pclabs.com.tr/gokhanozturk/2011/11/17/facebook-batch-requests-php-class/
class facebook_batch {
protected $requests = array();
protected $responses = null;
protected $cur = 1;
protected $map = array();
const MAX_NUMBER_OF_REQUESTS = 20;
public function add($path, $method = 'GET', $params = array(), $extra = array()) {
if(count($this->requests) > self::MAX_NUMBER_OF_REQUESTS) return false;
$path = trim($path, '/ ');
$body = http_build_query($params);
$body = urldecode($body);
if(strtolower($method) == 'get') {
if(count($params) > 0) {
$path .= "?" . $body;
$body = "";
}
}
$key = $this->cur++;
$this->requests[$key] = array_merge(array('relative_url' => $path, 'method' => $method, 'body' => $body), $extra);
return intval($key);
}
public function remove($key) {
unset($this->requests[$key]);
}
public function execute() {
global $facebook;
$i = 0;
foreach($this->requests as $k => $r) {
$this->map[$k] = $i++;
}
$batch = json_encode(array_values($this->requests));
$params = array('batch' => $batch);
$this->responses = $facebook->api('/', 'POST', $params);
}
public function response($key) {
if(! $this->responses) $this->execute();
$rkey = $this->map[intval($key)];
$resp = $this->responses[intval($rkey)];
if($resp['code'] != 200) return false;
return json_decode($resp['body'], true);
}
public function getRequests() {
return $this->requests;
}
}
?>
I added a null check to mine:
$friends_locations = $facebook->api_client->fql_query('SELECT name,birthday_date, pic_square FROM user WHERE uid in (SELECT uid2 from friend where uid1='. $user_id .') and birthday_date > 0');
Just an update for the new graph Batch API: You can also execute that as follows:
// Save your method calls into an array
$queries = array(
array('method' => 'GET', 'relative_url' => '/me'),
array('method' => 'GET', 'relative_url' => '/me/groups')
);
// POST your queries to the batch endpoint on the graph.
$batchResponse = $facebook->api('?batch='.json_encode($queries), 'POST');
// Return values are indexed in order of the original array, content is in ['body'] as a JSON
// string. Decode for use as a PHP array.
$user_profile = json_decode($batchResponse[0]['body'], true);
$user_groups = json_decode($batchResponse[1]['body'], true);
That should do the trick.
Facebook recommends using FQL for this; http://developers.facebook.com/docs/guides/performance by combining your requests in a (nested) query.
Their own example:
$friends_locations = $facebook->api_client->fql_query(
'SELECT hometown_location from user where uid in ' .
'(SELECT uid2 from friend where uid1=' . $user_id . ')');
If your requests aren't dependant on eachother you can use fql.multiquery