11 min read

Mock AJAX and your Facebook profile

I’m sure that you’ve heard of AJAX (Asynchronous JavaScript and XML) with which you can build interactive web pages. Well, Facebook has Mock AJAX, and with this you can create interactive elements within a profile page. Mock AJAX has three attributes that you need to be aware of:

  • clickwriteform: The form to be used to process any data.
  • clickwriteid: The id of a component to be used to display our data.
  • clickwriteurl: The URL of the application that will process the data.

When using Mock AJAX, our application must do two things:

  • Return the output of any processed data (and we can do that by using either echo or print).
  • Define a form with which we’ll enter any data, and a div to receive the processed data

Using a form on your profile

Since we want to make our application more interactive, one simple way is to add a form. So, for our first example we can add a function (or in this case a set of functions) to appinclude.php that will create a form containing a simple combo-box:

function country_combo () {
/*You use this function to display a combo-box containing
a list of countries. It's in its own function so that we
can use it in other forms without having to add any
extra code*/
$country_combo = <<<EndOfText
<select name=sel_country>
<option>England</option>
<option>India</option>
</select>
EndOfText;
return $country_combo;
}
function country_form () {
/*Like country_combo-box we can use this form where ever
needed because we've encapsulated it in its own function */
global $appcallbackurl;
$country_form = "<form>";
$country_form .= country_combo ();
$country_form .= <<<EndOfText
<input type="submit"
clickrewriteurl="$appcallbackurl"
clickrewriteid="info_display" value="View Country"
/>
<div id="info_display" style="border-style: solid;
border-color: black;
border-width: 1px; padding: 5px;">
No country selected
</div>
</form>
EndOfText;
return $country_form;
}
function display_simple_form () {
/*This function displays the country form with
a nice subtitle (on the Profile page)*/
global $facebook, $_REQUEST;
#Return any processed data
if (isset($_REQUEST['sel_country'])) {
echo $_REQUEST['sel_country'] . " selected";
exit;
}
#Define the form and the div
$fbml_text = <<<EndOfText
<fb:subtitle>
<fb:name useyou=false uid=$user firstnameonly=true
possessive=true> </fb:name>
Suspect List
</fb:subtitle>
EndOfText;
$fbml_text .= country_form ();
$facebook->api_client->profile_setFBML($fbml_text, $user);
echo $fbml_text;
}

And, of course, you’ll need to edit index.php:

display_simple_form ();

You’ll notice from the code that we need to create a div with the id info_display, and that this is what we use for the clickrewriteid of the submit button. You’ll also notice that we’re using $appcallbackurl for the clickrewriteurl ($appcallbackurl is defined in appinclude.php).

Now, it’s just a matter of viewing the new FMBL (by clicking on the application URL in the left-navigation panel):

Building a Facebook Application: Part 2

If you select a country, and then click on View Country, you’ll see:

Building a Facebook Application: Part 2

I’m sure that you can see where we’re going with this. The next stage is to incorporate this form into our Suspect Tracker application. And the great thing now is that because of the functions that we’ve already added to appinclude.php, this is now a very easy job:

function first_suspect_tracker () {
global $facebook, $_REQUEST;
if (isset($_REQUEST['sel_country'])) {
$friend_details = get_friends_details_
by_country ($_REQUEST['sel_country']);
foreach ($friend_details as $friend) {
$div_text .=
"<fb:name uid=" . $friend['uid'] .
" firstnameonly=false></fb:name>, ";
}
echo $div_text;
exit;
}
$fbml_text .= country_form ();
$facebook->api_client->profile_setFBML($fbml_text, $user);
$facebook->redirect($facebook->get_facebook_url() . '/profile.php');
}

You may also want to change the country_form function, so that the submit button reads View Suspects. And, of course, we’ll also need to update index.php. Just to call our new function:

<?php
require_once 'appinclude.php';
first_suspect_tracker ();
?>

This time, we’ll see the list of friends in the selected country:

Building a Facebook Application: Part 2

or:

Building a Facebook Application: Part 2

OK, I know what you’re thinking, this is fine if all of your friends are in England and India, but what if they’re not? And you don’t want to enter the list of countries manually, do you? And what happens if someone from a country not in the list becomes your friend? Obviously, the answer to all of these questions is to create the combo-box dynamically.

Creating a dynamic combo-box

I’m sure that from what we’ve done so far, you can work out how to extract a list of countries from Facebook:

function country_list_sql () {
/*We're going to be using this piece of SQL
quite often so it deserves its own function*/
global $user;
$country_list_sql = <<<EndSQL
SELECT hometown_location.country
FROM user
WHERE uid IN (SELECT uid1
FROM friend
WHERE uid2=$user)
EndSQL;
return $country_list_sql;
}
function full_country_list () {
/*With the SQL in a separate function this
one is very short and simple*/
global $facebook;
$sql = country_list_sql ();
$full_country_list = $facebook->
api_client->fql_query($sql);
print_r ($full_country_list);
}

However, from the output, you can see that there’s a problem with the data:

Building a Facebook Application: Part 2

If you look through the contents of the array, you’ll notice that some of the countries are listed more than once—you can see this even more clearly if we simulate building the combo-box:

function options_country_list () {
global $facebook;
$sql = country_list_sql ();
$country_list = $facebook->api_client->fql_query($sql);
foreach ($country_list as $country){
echo "option:" . $country['hometown_location']
['country'] ."<br>";
}
}

From which, we’d get the output:

Building a Facebook Application: Part 2

This is obviously not what we want in the combo-box.

Fortunately, we can solve the problem by making use of the array_unique method, and we can also order the list by using the sort function:


function filtered_country_list () {
global $facebook;
$sql = country_list_sql ();
$country_list = $facebook->api_client->
fql_query($sql);
$combo_full = array();
foreach ($country_list as $country){
array_push($combo_full, $country[
'hometown_location']['country']);
}
$combo_list = array_unique($combo_full);
sort($combo_list);
foreach ($combo_list as $combo){
echo "option:" . $combo ."<br>";
}
}

And now, we can produce a usable combo-box:

Building a Facebook Application: Part 2

Once we’ve added our code to include the dynamic combo-box, we’ve got the workings for a complete application, and all we have to do is update the country_combo function:

function country_combo () {
/*The function now produces a combo-box
derived from the friends' countries */
global $facebook;
$country_combo = "<select name=sel_country>";
$sql = country_list_sql ();
$country_list = $facebook->api_client->fql_query($sql);
$combo_full = array();
foreach ($country_list as $country){
array_push($combo_full, $country[
'hometown_location']['country']);
}
$combo_list = array_unique($combo_full);
sort($combo_list);
foreach ($combo_list as $combo){
$country_combo .= "<option>" . $combo ."</option>";
}
$country_combo .= "</select>";
return $country_combo;
}

Of course, you’ll need to reload the application via the left-hand navigation panel for the result:

Building a Facebook Application: Part 2

Limiting access to the form

You may have spotted a little fly in the ointment at this point. Anyone who can view your profile will also be able to access your form and you may not want that (if they want a form of their own they should install the application!). However, FBML has a number of if (then) else statements, and one of them is <fb:if-is-own-profile>:

<?php
require_once 'appinclude.php';
$fbml_text = <<<EndOfText
<fb:if-is-own-profile>
Hi <fb:name useyou=false uid=$user firstnameonly=true></fb:name>,
welcome to your Facebook Profile page.
<fb:else>
Sorry, but this is not your Facebook Profile page -
it belongs to <fb:name useyou=false uid=$user
firstnameonly=false> </fb:name>,
</fb:else>
</fb:if-is-own-profile>
EndOfText;
$facebook->api_client->profile_setFBML($fbml_text, $user);
echo "Profile updated";
?>

So, in this example, if you were logged on to Facebook, you’d see the following on your profile page:

Building a Facebook Application: Part 2

But anyone else viewing your profile page would see:

Building a Facebook Application: Part 2

And remember that the FBML is cached when you run:

$facebook->api_client->profile_setFBML($fbml_text, $user);

Also, don’t forget, it is not dynamic that is it’s not run every time that you view your profile page. You couldn’t, for example, produce the following for a user called Fred Bloggs:

Sorry Fred, but this is not Your Facebook Profile page – it belongs to Mark Bain

That said, you are now able to alter what’s seen on the screen, according to who is logged on.

Storing data—keeping files on your server

From what we’ve looked at so far, you already know that you not only have, but need, files stored on your server (the API libraries and your application files). However, there are other instances when it is useful to store files there.

Storing FBML on your server

In all of the examples that we’ve worked on so far, you’ve seen how to use FBML mixed into your code. However, you may be wondering if it’s possible to separate the two. After all, much of the FBML is static—the only reason that we include it in the code is so that we can produce an output. As well as there may be times when you want to change the FBML, but you don’t want to have to change your code every time you do that (working on the principle that the more times you edit the code the more opportunity there is to mess it up).

And, of course, there is a simple solution.

Let’s look at a typical form:

<form>
<div id="info_display" style="border-style: solid;
border-color: black;
border-width: 1px; padding: 5px;">
</div>
<input name=input_text>
<input type="submit"
clickrewriteurl="http://213.123.183.16/f8/penguin_pi/"
clickrewriteid="info_display" value="Write Result">
</form>

Rather than enclosing this in $fbml_text = <<<EndOfText … EndOfText; as we have done before, you can save the FBML into a file on your server, in a subdirectory of your application. For example /www/htdocs/f8/penguin_pi/fbml/form_input_text.fbml.

“Aha” I hear your say, “won’t this invalidate the caching of FBML, and cause Facebook to access my server more often than it needs?”

Well, no, it won’t. It’s just that we need to tell Facebook to update the cache from our FBML file. So, first we need to inform FBML that some external text needs to be included, by making use of the <fb:ref> tag, and then we need to tell Facebook to update the cache by using the fbml_refreshRefUrl method:

function form_from_server () {
global $facebook, $_REQUEST, $appcallbackurl, $user;
$fbml_file = $appcallbackurl . "fbml/form_input_text.fbml";
if (isset($_REQUEST['input_text'])) {
echo $_REQUEST['input_text'];
exit;
}
$fbml_text .= "<fb:ref url='" . $fbml_file . "' />";
$facebook->api_client->profile_setFBML($fbml_text, $user);
$facebook->api_client->fbml_refreshRefUrl($fbml_file);
echo $fbml_text;
}

As far as your users are concerned, there is no difference. They’ll just see another form on their profile page:

Building a Facebook Application: Part 2

Even if your users don’t appreciate this leap forward, it will make a big difference to your coding—you’re now able to isolate any static FBML from your PHP (if you want).

And now, we can turn our attention to one of the key advantages of having your own server—your data.

Storing data on your server

So far, we’ve concentrated on how to extract data from Facebook and display it on the profile page. You’ve seen, for example, how to list all of your friends from a given country. However, that’s not how Pygoscelis’ list would work in reality. In reality, you should be able to select one of your friends and add them to your suspect list. We will, therefore, spend just a little time on looking at creating and using our own data.

We’re going to be saving our data in files, and so your first job must be to create a directory in which to save those files. Your new directory needs to be a subdirectory of the one containing your application. So, for example, on my Linux server I would do:

cd /www/htdocs/f8/penguin_pi      

#Move to the application directory

mkdir data

#Create a new directory

chgrp www-data data                         

#Change the group of the directory

chmod g+w data                                 

#Ensure that the group can write to data

LEAVE A REPLY

Please enter your comment!
Please enter your name here