fb_form.module in Drupal for Facebook 5
Same filename and directory in other branches
This module defines facebook-specific form elements for use with Drupal's form API.
It also defines commonly used forms, for example a form to invite friends to install an application.
File
fb_form.moduleView source
<?php
/**
* @file
*
* This module defines facebook-specific form elements for use with Drupal's
* form API.
*
* It also defines commonly used forms, for example a form to invite friends
* to install an application.
*/
// There's some obsolete and experimental code in this module. Everything may change! Watch out for things labelled deprecated.
/**
* hook_menu.
*/
function fb_form_menu($may_cache) {
$items = array();
if ($may_cache) {
// Page allowing a user to invite their friends to add the app.
$items[] = array(
'path' => 'fb/invite',
'callback' => 'fb_form_invite_page',
'access' => TRUE,
'type' => MENU_CALLBACK,
);
}
return $items;
}
/**
* hook_form_alter.
*/
function fb_form_form_alter($form_id, &$form) {
// Drupal allows no clean way to set $form['#type'], so we hack.
if ($type = $form['#fb_form_type_hack']) {
$form['#type'] = $type;
unset($form['#fb_form_type_hack']);
}
// Support for ahah (see ahah_forms.module)
if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) {
$form['#after_build'][] = 'fb_ahah_bind_form';
}
}
/**
* Support for AHAH in forms.
*
* This is intended to be compatible with the syntax of ahah_forms.module.
* However, much of what that module does requires jquery. In FBML we have to
* jquery and are therefor limited in what we can support. For example, we
* only support the id selectors, you can't specify selector in your
* ahah_bindings.
*/
function fb_ahah_bind_form($form) {
static $one_time_only;
// Facebook javascript appears to work only when the user is logged in. Not
// sure whether this is on purpose or not. So we only activate AHAH when
// user is logged in.
global $fb;
if ($fb && $fb->api_client->added && function_exists('ahah_forms_scan_form_children')) {
$bindings = array();
ahah_forms_scan_form_children($form, $form['#id'], $bindings);
// drupal_set_message( "After Scan: Wrapper Bindings = " . dprint_r( $bindings, TRUE ) );
if (count($bindings) > 0) {
if (!$one_time_only) {
//add in required javascript files
$module_path = drupal_get_path('module', 'ahah_forms');
fb_add_js(drupal_get_path('module', 'fb_form') . '/fb_ahah_forms.js');
drupal_add_js(array(
'ahah' => array(
'basePaths' => array(
'base' => base_path(),
'module' => $module_path,
),
'bindings' => array(
$bindings,
),
),
), 'setting', 'fbjs');
$one_time_only = TRUE;
}
else {
drupal_add_js(array(
'ahah' => array(
'bindings' => array(
$bindings,
),
),
), 'setting', 'fbjs');
}
}
}
return $form;
}
/**
* Create a page to invite friends to add an app.
*
* This page will succeed only if:
* - shown on a canvas page
* - it is an FBML canvas page, not an iframe
* - the current user has added the application (not sure about this)
*/
function fb_form_invite_page() {
global $fb, $fb_app;
if (function_exists('fb_canvas_is_fbml') && !fb_canvas_is_fbml()) {
drupal_set_message(t('Unable to display page. FBML required.'), 'error');
drupal_not_found();
exit;
}
if ($fb_app) {
drupal_set_title(t('Invite friends to use %application', array(
'%application' => $fb_app->title,
)));
}
$output = drupal_get_form('fb_form_multi_add_invite_form');
return $output;
}
/**
* Create a form allowing the user to invite friends to add the app.
*
* Facebook provides a very specific way to build this form using FBML. This will only display properly on FBML canvas pages.
* The FBML for this form requires the <fb:request-form> tag where the <form> tag would normally be. Also the form provides its own buttons. These two things make it difficult to use Drupal's Form API to build the form. Still, we use FAPI, because we want modules to be able to alter the form (i.e. to add descriptive text). Alteration that rely on #submit or even additional input fields will probably not work properly, however.
*/
function fb_form_multi_add_invite_form() {
global $fb, $fb_app;
// TODO: confirm that we're displaying an FBML canvas page.
if ($fbu = fb_facebook_user($fb)) {
// Exclude friends who have already installed app.
// http://wiki.developers.facebook.com/index.php/Fb:request-form
$rs = $fb->api_client
->fql_query("SELECT uid FROM user WHERE has_added_app=1 and uid IN (SELECT uid2 FROM friend WHERE uid1 = {$fbu})");
$arFriends = "";
// Build an delimited list of users...
if ($rs) {
$arFriends .= $rs[0]["uid"];
for ($i = 1; $i < count($rs); $i++) {
if ($arFriends != "") {
$arFriends .= ",";
}
$arFriends .= $rs[$i]["uid"];
}
}
}
// Use node body in invite message.
$node = node_load($fb_app->nid);
$node = node_prepare($node);
$content = $node->teaser;
// Do we need to append &next=[someURL] to the url here?
$content .= "<fb:req-choice url=\"http://www.facebook.com/add.php?api_key={$fb_app->api_key}\" label=\"" . t('Add !title application.', array(
'!title' => $fb_app->title,
)) . " />";
// form type fb:request-form
$form = array(
'#fb_form_type_hack' => 'fb_form_request',
/* becomes #type during form_alter */
'#attributes' => array(
'type' => $fb_app->title,
'content' => htmlentities($content),
'invite' => 'true',
),
'#action' => 'http://apps.facebook.com/' . $fb_app->canvas,
);
$form['friends'] = array(
'#type' => 'fb_form_request_selector',
'#title' => t('Select the friends to invite.'),
'#attributes' => array(
'exclude_ids' => $arFriends,
),
);
return $form;
}
/**
* Helper function to produce a request or invite form. Note that this does
* not produce a full form (i.e. never use
* drupal_get_form('fb_form_request_form')). The caller is expected to fill
* out the rest of the form before returning it for use with drupal_get_form.
*/
function fb_form_request_form($config = array()) {
global $fb, $fb_app;
// only works on canvas pages.
// Default config
$config = array_merge(array(
'type' => $fb_app->title,
'content' => 'INVITE CONTENT XXX',
'action' => 'http://apps.facebook.com/' . $fb_app->canvas,
'invite' => 'true',
'method' => 'POST',
), $config);
// form type fb:request-form
$form = array(
'#fb_form_type_hack' => 'fb_form_request',
/* becomes #type during form_alter */
'#attributes' => array(
'type' => $config['type'],
'content' => htmlentities($config['content']),
'invite' => $config['invite'],
),
'#action' => $config['action'],
);
// Caller must add fb:multi-friend-selector or some other selector.
return $form;
}
/**
* Based on theme_form, this renders an fb:request-form.
*/
function theme_fb_form_request($element) {
// TODO: verify attributes required by facebook are found.
// Anonymous div to satisfy XHTML compliance.
$action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : '';
$output = '<fb:request-form ' . $action . ' method="' . $element['#method'] . '" ' . 'id="' . $element['#id'] . '"' . drupal_attributes($element['#attributes']) . ">\n<div>" . $element['#children'] . "\n</div></fb:request-form>\n";
return $output;
}
// Because the fb:request-form includes its own buttons, including the particularly annoying skip button, this submit callback is not used. Will probably delete it. If I can't make it work properly.
function fb_form_multi_add_invite_form_submit() {
//watchdog('fb_debug', 'fb_form_multi_add_invite_form_submit' . dprint_r(func_get_args(), 1));
//return "foo/bar";
}
function fb_form_group_options($fbu) {
$groups = fb_get_groups_data($fbu);
$items = array();
if ($groups && count($groups)) {
foreach ($groups as $data) {
$items[$data['gid']] = $data['name'];
}
}
// TODO: alphabetize list
return $items;
}
// TODO: make this work whether in canvas page or not.
function fb_form_friend_options($fbu) {
global $fb;
$items = array();
if ($fb) {
$query = "SELECT last_name, first_name, uid, pic_square FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={$fbu})";
$result = $fb->api_client
->fql_query($query);
// TODO: sort results by name
foreach ($result as $data) {
$items[$data['uid']] = $data['first_name'] . ' ' . $data['last_name'];
}
}
return $items;
}
function fb_form_group_member_options($fbg, $fbu) {
global $fb;
$query = "SELECT uid FROM group_member WHERE gid={$fbg}";
$result = $fb->api_client
->fql_query($query);
drupal_set_message("fb_form_group_member_options({$fbg}, {$fbu}) query {$query} returns" . dpr($result, 1));
$query = "SELECT uid, first_name, last_name FROM user WHERE uid IN (SELECT uid FROM group_member WHERE gid={$fbg})";
$result = $fb->api_client
->fql_query($query);
drupal_set_message("fb_form_group_member_options({$fbg}, {$fbu}) query {$query} returns" . dpr($result, 1));
// TODO: sort results by name
$options = array();
foreach ($result as $data) {
if ($data['uid'] != $fbu) {
$options[$data['uid']] = $data['first_name'] . ' ' . $data['last_name'];
}
}
return $options;
}
function fb_form_elements() {
$items = array();
$items['fb_form_request_selector'] = array(
'#input' => TRUE,
'#tree' => TRUE,
/* not sure what this does */
'#process' => array(
'fb_form_process_request_selector' => array(),
),
// The submit callback does not work properly in <fb:request-form>
'#executes_submit_callback' => TRUE,
);
/* deprecated */
$items['friend_selector'] = array(
'#input' => TRUE,
'#tree' => TRUE,
'#process' => array(
'friend_selector_process' => array(),
),
);
return $items;
}
/**
* Build a friend selector for use in <fb:request-form>.
*
* Use this to select friends when sending an invite or request.
*/
function fb_form_process_request_selector($orig) {
global $fb;
// replace with FBML markup
$element = array(
'#type' => 'markup',
'#value' => '<fb:multi-friend-selector ',
);
if (!$orig['#attributes']) {
$orig['#attributes'] = array();
}
// Use title for actiontext
if (!$orig['#attributes']['actiontext']) {
$orig['#attributes']['actiontext'] = $orig['#title'];
}
$element['#value'] .= drupal_attributes($orig['#attributes']);
// Some settings for FAPI.
foreach (array(
'#parents',
'#weight',
'#name',
'#id',
'#input',
'#required',
) as $key) {
if (isset($orig[$key])) {
$element[$key] = $orig[$key];
}
}
$element['#value'] .= ' />';
/* close tag */
return $element;
}
/* deprecated */
function friend_selector_process($orig) {
global $fb;
if (!$fb) {
// TODO: Handle this better.
return;
}
static $options = NULL;
if (!$options) {
$query = "SELECT last_name, first_name, uid, pic_square FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=" . fb_facebook_user() . ")";
$result = $fb->api_client
->fql_query($query);
// TODO: sort results by name
$options = array();
foreach ($result as $data) {
$options[$data['uid']] = $data['first_name'] . ' ' . $data['last_name'];
}
}
// TODO: display small picture along with name in select box.
$element = array();
foreach (array(
'#title',
'#parents',
'#description',
'#default_value',
'#weight',
'#multiple',
'#required',
'#name',
'#value',
) as $key) {
if (isset($orig[$key])) {
$element[$key] = $orig[$key];
}
}
$element['#type'] = 'select';
$element['#options'] = $options;
//drupal_set_message("fb_form processed " . dpr($orig, 1) . " into " . dpr($element, 1));
return $element;
}
function friend_selector_value(&$form) {
//drupal_set_message("friend_selector_value" . dpr($form, 1));
}
// TODO: provide some alternative when NOT a facebook app.
// deprecated!
function theme_friend_selector($fbu = NULL) {
drupal_set_message("theme_friend_selector");
if (!$fbu) {
$fbu = fb_facebook_user();
}
$output = "<fb:friend-selector uid=\"{$fbu}\" name=\"fbname\" idname=\"fbu\" />";
return $output;
}
Functions
Name | Description |
---|---|
fb_ahah_bind_form | Support for AHAH in forms. |
fb_form_elements | |
fb_form_form_alter | hook_form_alter. |
fb_form_friend_options | |
fb_form_group_member_options | |
fb_form_group_options | |
fb_form_invite_page | Create a page to invite friends to add an app. |
fb_form_menu | hook_menu. |
fb_form_multi_add_invite_form | Create a form allowing the user to invite friends to add the app. |
fb_form_multi_add_invite_form_submit | |
fb_form_process_request_selector | Build a friend selector for use in <fb:request-form>. |
fb_form_request_form | Helper function to produce a request or invite form. Note that this does not produce a full form (i.e. never use drupal_get_form('fb_form_request_form')). The caller is expected to fill out the rest of the form before returning it for use… |
friend_selector_process | |
friend_selector_value | |
theme_fb_form_request | Based on theme_form, this renders an fb:request-form. |
theme_friend_selector |