Navigation

Related Articles

Back to Latest Articles

Exemple d’application utilisant la Graph API de Facebook


laurent
Exemple d’application utilisant la...

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.

Show Comments (8)

Comments

  • Steph

    Bonjour !
    J’ai suivi votre tuto pour essayer d’avoir une démo d’application facebook qui fonctionne mais j’ai plusieurs problèmes…
    Tout d’abord j’ai modifié routing.yml pour être redirigé vers mon module quand je vais sur http://127.0.0.1/frontend_dev.php/
    Le 1er problème est que j’ai une erreur « cancel_url is not owned by this application » ou quelque chose comme ça quand j’allais sur 127.0.0.1/frontend_dev.php/demo/login parce que dans les paramètres GET de l’url il y avait cancel_url=http://127.0.0.1/frontend_dev.php/demo/login alors j’ai fini par le supprimer de l’URL et là j’ai eu la demande d’autorisation d’accéder à mes infos personnelles.
    Le plus gros problème surgit dans le try/catch de la méthode executeIndex dans actions.class.php à la ligne $this->fbme = $this->facebook->api(‘/me’); et de ce fait mon appli tourne en rond car elle essaie sans cesse d’atteindre la page demo/login (car il y a une redirection dans le catch…)

    Bref, je ne sais pas si j’ai été clair mais avez-vous rencontré un problème de ce type ? Savez-vous comment je peux arranger ça ?

    Merci beaucoup !

    • Article Author
  • Steph

    Bonjour !
    J\’ai suivi votre tuto pour essayer d\’avoir une démo d\’application facebook qui fonctionne mais j\’ai plusieurs problèmes…
    Tout d\’abord j\’ai modifié routing.yml pour être redirigé vers mon module quand je vais sur http://127.0.0.1/frontend_dev.php/
    Le 1er problème est que j\’ai une erreur \"cancel_url is not owned by this application\" ou quelque chose comme ça quand j\’allais sur 127.0.0.1/frontend_dev.php/demo/login parce que dans les paramètres GET de l\’url il y avait cancel_url=http://127.0.0.1/frontend_dev.php/demo/login alors j\’ai fini par le supprimer de l\’URL et là j\’ai eu la demande d\’autorisation d\’accéder à mes infos personnelles.
    Le plus gros problème surgit dans le try/catch de la méthode executeIndex dans actions.class.php à la ligne $this->fbme = $this->facebook->api(\’/me\’); et de ce fait mon appli tourne en rond car elle essaie sans cesse d\’atteindre la page demo/login (car il y a une redirection dans le catch…)

    Bref, je ne sais pas si j\’ai été clair mais avez-vous rencontré un problème de ce type ? Savez-vous comment je peux arranger ça ?

    Merci beaucoup !

    • Article Author
  • Yann

    Bonjour,
    Merci pour ce tuto encore une fois très bien détaillé. =)

    J’utilise la méthode $this->facebook->api(‘/me/feed’, ‘post’, $params) pour poster sur le mur de l’utilisateur actif depuis mon action.
    Mon array $params contient les données ‘link’, ‘picture’, ‘message’, ‘name’, ‘caption’, ‘description’, ‘action’.

    J’ai remarqué que certaines applis Facebook lorsqu’elles postent sur le mur, incluent des liens dans la description (ex: http://img208.imageshack.us/img208/6784/applifb.jpg) sous la forme 1: lien, 2: lien…

    J’ai du mal à trouver de la doc sur ce point précis, à tout hasard, savez-vous comment gérer cela ?

    • Article Author
  • copy/paste » Eviter la boucle infinie sur une application Facebook avec symfony

    […] application sur facebook, ne sachant plus écrire du PHP sans symfony ,  je me suis basé sur ce tutorial de lexik pour mener ma tâche à […]

    • Article Author
  • Séb

    Bonjour,
    En utilisant cette méthode, j’ai un problème : lorsque j’essaye de me connecter à l’application sur facebook, l’application se recharge en boucle au moment de la connexion, comme si la connexion ne se faisait pas et que facebook redirige donc vers la connexion en permanence…
    Est ce que vous auriez une idée de ce qui se passe ??
    Je constate exactement la même chose avec votre application exemple.
    Merci !

    • Article Author
  • Ayoub

    @Séb j’ai eu le même problème avec la boucle infinie tu peux consulter une solution que j’ai bricolé ici http://blog.ayoubhidri.com/2011/06/03/eviter-la-boucle-infinie-sur-une-application-facebook-avec-symfony/

    • Article Author
  • Niko

    Hello!
    Dans le même genre d’idée, j’aimerais savoir comment publier un même contenu sur plusieurs murs à la fois ..et en une seule fois.
    En parcourant ce post je vois qu’il existe une fonction publishWall() ce qui le fait penser que c’est possible mais avant de m’y lancer je pose la question au cas où quelqu’un aurai déjà étudié la question.
    Déjà… est ce que c’est possible ? comment ?
    Merci à vous 😉
    Niko

    • Article Author
  • crogiez

    bonjour
    j’ai une appli facebook qui recupere les email des users
    elle est sur cloud d’heroku en https:\
    comment feriez vous pour les stocker dans une data base ou ailleurs
    merci

    • Article Author

Recevez nos articles