Exemple d’application utilisant la Graph API de Facebook

Facebook a lancé il y a maintenant quelques mois sa nouvelle Graph API, qui permet d’accèder et d’interagir avec les informations Facebook de l’utilisateur encore plus simplement. Seuelement la documentation qui l’entoure se fait encore rare et peu détaillée. Je vais donc profiter de cet article pour présenter quelques aspects de cette nouvelle API à l’aide d’une petite iframe application Facebook, et avec Symfony (pour rester dans la thématique du blog !).

Pour commencer nous avons bien sûr besoin de créer notre application Facebook. Cela n’étant pas le but de cet article, je vous laisse trouver la marche à suivre sur le net; les sites couvrant le sujet sont légion (par exemple créer une application Facebook).

On paramètre correctement l’application et celle-ci s’occupera ensuite de charger nos pages dynamiques depuis l’url spécifiée:

L’application Symfony n’a ici qu’un seul module « demo » qui s’occupe des quelques actions nécessaires. Editons « app.yml » pour y ajouter l’ID et le SECRET obtenus lors de la création de notre application:

all:
  facebook:
    app_id: 116399618389033
    api_key: *******************************************
    secret: *****************************************
    base_url: http://facebook.prestataire-symfony.com
    app_url: http://apps.facebook.com/demolexik

Il nous faut ensuite récupérer l’api Facebook PHP sur Github, que nous allons coller dans /lib/facebook/facebook.php.
Afin de ne pas avoir à initialiser les appels à l’api depuis chaque action, un filter va grandement nous simplifier la tâche:

// lib/filter/FacebookFilter.class.php
class FacebookFilter extends sfFilter
{
 
  public function execute(sfFilterChain $filterChain)
  {
    $context = $this->getContext();
    $request = $context->getRequest();
    //initialisation de l'appel à l'api...
    $facebook = new Facebook(array(
          'appId'   => sfConfig::get('app_facebook_app_id'),
          'secret'  => sfConfig::get('app_facebook_secret'),
          'cookie'  => true,
      ));
 
    $context->getController()
            ->getActionStack()
            ->getLastEntry()
            ->getActionInstance()
            ->facebook = $facebook;
 
    $filterChain->execute();
  }
}

Pensez à éditer votre « filters.yml » en conséquence.

#apps/frontend/config/filters.yml
rendering: ~
security:  ~
# insert your own filters here
Facebook:
  class: FacebookFilter
cache:     ~
execution: ~

Pour l’api Javascript, nous allons éditer le layout de l’application:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
  <head>
    <?php include_http_metas() ?>
    <?php include_metas() ?>
    <title>Facebook App</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>
    <style>
      div.section {
        margin-bottom: 10px;
        background: #EEEEEE;
        padding: 5px 10px;
      }
      body {
        font-family: Arial;
        font-size: 12px;
      }
      pre {
        font-size: 10px;
        color: #333333;
        margin-left: 50px;
      }
    </style>
  </head>
  <body>
    <div id="fb-root"></div>
    <script src="http://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
    <script type="text/javascript">
    FB.init({
       appId  : '<?php echo sfConfig::get('app_facebook_app_id') ?>',
       status : true, // vérifie le status de la connection
       cookie : true, // autorise les cookies pour permettre au serveur d'accéder à la session'
       xfbml  : true  // active le parsing de XFBML
      });
    </script>
    ...

Nous en profitons pour charger JQuery afin de faciliter l’ajax et le remaniement du Dom.

Voilà, nous sommes prêts à attaquer les actions.

La première action va être l’authentification de l’utilisateur Facebook, et la gestion des permissions que celui-ci devra accorder à notre application.
Le nouveau modèle de Facebook veut que nous demandions à l’utilisateur, dès le premier accès à l’application, qu’il accepte simultanément toutes les permissions nécessaires. Pour plus d’informations à ce sujet, consultez la liste des permissions sur le wiki Facebook Developer.
Voici l’action Login, qui sera appelée lorsque l’utilisateur n’a pas accordé ces permissions, ou lors d’une première visite de l’application:

//apps/frontend/modules/demo/actions/actions.class.php
public function executeLogin(sfWebRequest $request)
  {
    //on génère l'url qui permettra le login à l'application
    $this->loginUrl = $this->facebook->getLoginUrl(array(
            'canvas'    => 1,
            'fbconnect' => 0,
            //ici on demande les permissions email, publication sur le mur, et changement du status
            'req_perms' => 'email,publish_stream,status_update',
            'next'      => ''
        ));
  }

Comme nous sommes dans une application iframe, il faut charger l’url de login depuis la frame parente, et notre template va s’en charger:

<!--loginSuccess.php-->
<script type="text/javascript">
top.location.href = "<?php echo $sf_data->getRaw('loginUrl') ?>";
</script>

Il faut maintenant que notre index redirige vers ce login dans les cas précédemment cités:

//apps/frontend/modules/demo/actions/actions.class.php
public function executeIndex(sfWebRequest $request)
  {
    //on vérifie si l'utilisateur a une session facebook active
    $this->session = $this->facebook->getSession();
    if (!$this->session)
    {
      //sinon il doit s'identifier
      $this->redirect('demo/login');
    }
 
    //s'il a une session active, on vérifie si elle est valide pour notre application
    try
    {
      $this->uid = $this->facebook->getUser();
      $this->fbme = $this->facebook->api('/me');
    }
    catch (FacebookApiException $e)
    {
      //sinon il doit à nouveau s'identifier
      $this->redirect('demo/login');
    }
  }

On peut maintenant voir une demande de permissions s’afficher lorsque l’on se connecte à l’application:

En vérifiant la validité de la session, nous avons récupéré toutes les informations sur l’utilisateur auxquelles nos permissions nous donnent accès. Voyons l’étendue de ces informations en les affichant dans notre vue:

<!-- indexSuccess.php -->
<div class="section">
<h3>Informations utilisateur</h3>
<pre><?php print_r($fbme) ?> /pre>
</div>


Nous accédons bien à l’adresse email comme spécifié, ainsi qu’aux informations génériques et publiques sur l’utilisateur.

Il est maintenant temps d’interagir avec l’utilisateur. Il nous a également accordé l’accès à son status, nous allons donc lui proposer de l’éditer via notre application:

<!-- indexSuccess.php -->
...
<div class="section">
  <a onclick="updateStatus();return false;" href="#">Changer mon status via Ajax et l'API PHP</a>
  <textarea id="status_text" cols="40" rows="2">  </textarea>
</div>
...
<script type="text/javascript">
function updateStatus()
  {
    var status = document.getElementById('status_text').value;
 
    $.ajax({
      type: 'post',
      url: '<?php echo url_for('demo/statusUpdate') ?>',
      data: 'status=' + status,
      success: function(response) {
        alert(response);
      },
      error: function(response) {
        alert(response);
      }
    });
  }
</script>

La méthode js « updateStatus() » va faire un appel ajax à une nouvelle action updateStatus de notre application:

//apps/frontend/modules/demo/actions/actions.class.php
public function executeUpdateStatus(sfWebRequest $request)
  {
    $this->forward404Unless($request->isXmlHttpRequest());
    $status = $request->getParameter('status');
    try
    {
      //un simple appel a l'api suffit à poster un nouveau status sur le profile de l'utilisateur
      $this->facebook->api(
          '/me/feed',
          'post',
          array( 'message' => $status, 'cb' => '' )
        );
    }
    catch (FacebookApiException $e)
    {
      return $this->renderText('Erreur: '.$e);
    }
    return $this->renderText('Status mis-à-jour');
  }

L’api Javascript est toute aussi simple à utiliser. Proposons cette fois à l’utilisateur de parler de notre application sur son mur à l’aide de javascript:

<!-- indexSuccess.php -->
...
<div class="section">
  <a onclick="publishWall();return false;" href="#">Poster un article sur mon mur via l'API Javascript</a>
</div>
...
<script type="text/javascript">
function publishWall()
  {
    FB.ui(
    {
      method: 'stream.publish',
      message: '',
      attachment:
      {
        name: "Démo Symfony+Facebook",
        caption: '',
        description: "Une démo simple d'application Facebook avec Symfony et les dernières API Javascript et PHP de Facebook.",
        href: "http://www.lexik.fr/blog/symfony/non-classe/exemple-dapplication-utilisant-la-graph-api-de-facebook-1187"
      },
      user_prompt_message: "Application de démo Symfony+Facebook"
    },
    function (response) {}
    );
  }
</script>

Le résultat obtenu en cliquant sur le lien est le pseudo-popup bien connu de Facebook:

Nous venons de voir quelques méthodes simples d’accès ou de publication de données. Une liste plus complète des méthodes éxistantes est sur le wiki Facebook Developer.
Dans le cadre d’applications plus complexes, il sera souvent utile de pouvoir formuler précisément les informations que l’on souhaite récupérer, et celles-ci ne correspondront pas nécessairement à une méthode éxistante. Pour cela Facebook met à notre disposition FQL, un langage de requète similaire à SQL dans sa syntaxe, pour générer nos requètes spécifiques.

Par exemple, récupérons la liste des amis de l’utilisateur avec leur nom, leur uid, et leur photo. Voici la requète FQL pour cela, et son éxécution via l’api PHP:

//apps/frontend/modules/demo/actions/actions.class.php
public function executeIndex(sfWebRequest $request)
  {
    ...
    //récupération des amis via FQL
    $query = "SELECT name, uid, pic_square FROM user WHERE uid in (SELECT uid2 FROM friend WHERE uid1 = ".$this->uid.")";
    $this->amis = $this->facebook->api(array(
        'method'    => 'fql.query',
        'query'     => $query,
        'callback'  => ''
    ));
  }

Et l’affichage de la liste dans la vue:

<!-- indexSuccess.php -->
<div class="section">
<h3>Liste d'amis</h3>
<?php foreach ($amis as $ami): ?>
<ul>
	<li><img src="<?php echo $ami['pic_square'] ?>" alt="" /></li>
	<li><strong><?php echo $ami ['name'] ?></strong></li>
	<li>uid: <?php echo $ami['uid'] ?></li>
</ul>
<?php endforeach; ?>
</div>

Cet article n’était pas dédié à Symfony, mais l’utilisait plutôt pour proposer un environnement familier à notre application. Ce survol rapide de la nouvelle Graph Api permet surtout de donner un point de départ sur l’utilisation de la nouvelle librairie à un moment ou la documentation à son sujet n’est pas vraiment fournie, en particulier en français !
Vous pouvez voir l’application tourner sur http://apps.facebook.com/demoLexik.

Partagez cet article