Facebook sdk api call function support polymorphic arguments. The fb_api function in fb module doesn't implement that. Here is new fb_api function that support that:

/**
 * Simple wrapper around $fb->api() which caches data.
 *
 * This is intended to avoid performace problems when, for example,
 * $fb->api('me') is called several times in a single request.
 */
function fb_api(/* polymorphic */) {
  static $cache;
  $fb = $GLOBALS['_fb'];
  if (!$fb) {
    return;
  }
  if (!isset($cache)) {
    $cache = array();
  }
  $func_args = func_get_args();
  $key = serialize($func_args);
  if (!isset($cache[$key])) {
	$cache[$key] = call_user_func_array(array($fb, 'api'), $func_args);
  }
  return $cache[$key];
}

Please, test and add it to the fb module.

Comments

Dave Cohen’s picture

Category: bug » feature
Status: Active » Needs work

The cache key should not be serialized. Each ID passed in should be stored individually, and ideally it would check each ID against the cache before calling $fp->api.

Remember, you can always call $fb->api() instead of fb_api(). You just wont get the caching. If youre careful about calling it, that won't matter.

oc666’s picture

The serialize is for cases when the fb->api need more than one argument. So, the serialize make this easy, and it's unique. That way, you can get unique cache key for multi-arguments function. Additionally, you get caching for the multi-arguments call and single argument as well.
For example, if you send argument 'me' to the function, the use 'me' string as a key is the same as the use of serialize(array('me')). You can check it yourself. It is the same if you send more than one argument.
The fb module should be full implemented for the facebook php-sdk, so this is drupal layer for facebook, so I think the use of fb_api instead of $fb->api is better, cause $fb is private for the layer (like object). The evidence for that is that the $fb source is $GLOBALS['_fb'] (the underline prefix of the variable means private property in object oriented programming).
I'm using the next code (after patching the fb module with function above) for creating album:

fb_api($fb_user . '/albums', 'POST', array("name" => $newAlbumName, "message" => $album_desc))

and it's working perfect.

Dave Cohen’s picture

The problem with the serialized key is this...

Let's say the first query is for IDs 'me' and '1234'. It won't use the cache because its the first query.

Next query is for just 'me'. It won't use the cache because 'me' does not exactly match the serialized key. In this case it should use the cache because we already queried for 'me'.

Next query is for '1234' and 'me'. Again, it will not use the cache because the serialized key has a different order. But again it should use the cache.

So the cache in your patch is only useful when you have the exact same IDs in the exact same order, which is unlikely.

The fb module should be full implemented for the facebook php-sdk

I disagree. Why create a layer that is just drupal-specific but adds nothing else? Facebook changes their APIs all the time and it would just be a lot of work for no gain. The reason to use fb_api() instead of $fb->api() is for the caching, as described in the comments in the code.

oc666’s picture

Let's say the first query is for IDs 'me' and '1234'. It won't use the cache because its the first query.

Next query is for just 'me'. It won't use the cache because 'me' does not exactly match the serialized key. In this case it should use the cache because we already queried for 'me'.

Next query is for '1234' and 'me'. Again, it will not use the cache because the serialized key has a different order. But again it should use the cache.

First of all, If someone call function with different order of arguments, it should behave differently. Polymorphic function should behave exactly like regular function, although, in this function the output would be the same but the caching would be differently.
Second, you could fix the problem you describe if you sort the array before serialize.

Why create a layer that is just drupal-specific but adds nothing else? Facebook changes their APIs all the time and it would just be a lot of work for no gain. The reason to use fb_api() instead of $fb->api() is for the caching, as described in the comments in the code.

From the fb module:

This set of modules and themes turns Drupal into a platform for developing Facebook Applications. This allows you to embed your content and features within facebook, or allow facebook users onto your site via Facebook Connect.

This module should be a platform, so we need to supply Drupal API for that. One that develop via this module doesn't know what is exactly $GLOBAL['_fb'] unless he study the code.