Más con Symfony

12.3. Facebook Connect

12.3.1. Cómo funciona Facebook Connect y cómo se puede integrar

El funcionamiento de Facebook Connect se basa en compartir su sesión con la sesión del sitio web. Para ello se copian las cookies de autenticación de Facebook en el sitio web mediante un <iframe> que se crea en el sitio web que apunta a una página de Facebook, que a su vez crea un <iframe> al sitio web. Como para realizar este proceso Facebook Connect debe tener acceso al sitio web, no es posible utilizar o probar Facebook Connect en un sitio web local o en una intranet. El punto de entrada es un archivo llamado xd_receiver.htm y que también proporciona el plugin sfFacebookConnectPlugin. Para que este archivo sea accesible, recuerda ejecutar la tarea plugin:publish-assets después de instalar el plugin.

Una vez hecho lo anterior, la librería oficial de Facebook ya puede utilizar la sesión de Facebook. Además, el plugin sfFacebookConnectPlugin crea un usuario de tipo sfGuard asociado con la sesión de Facebook, por lo que la integración con el sitio web de Symfony es completa. Este es el motivo por el que el plugin redirige por defecto a la acción sfFacebookConnectAuth/signIn después de pulsar el botón de Facebook Connect y una vez que la sesión de Facebook ha sido validada. El plugin primero busca algún usuario existente con ese UID de Facebook o con el mismo hash de email (como se explica más adelante). Si no se encuentra ningún usuario, se crea uno nuevo.

Otra estrategia común consiste en no crear directamente el usuario sino redirigirle a un formulario de registro propio. En ese formulario se pueden rellenar de forma automática todos los datos proporcionados por la sesión de Facebook, tal y como muestra el código del siguiente ejemplo:

public function setDefaultsFromFacebookSession()
{
  if ($fb_uid = sfFacebook::getAnyFacebookUid())
  {
    $ret = sfFacebook::getFacebookApi()->users_getInfo(
      array(
        $fb_uid
      ),
      array(
        'first_name',
        'last_name',
      )
    );

    if ($ret && count($ret)>0)
    {
      if (array_key_exists('first_name', $ret[0]))
      {
        $this->setDefault('first_name',$ret[0]['first_name']);
      }
      if (array_key_exists('last_name', $ret[0]))
      {
        $this->setDefault('last_name',$ret[0]['last_name']);
      }
    }
  }
}

Si se quiere utilizar esta segunda estrategia, simplemente se debe indicar en el archivo app.yml que después de conectar con Facebook Connect se redirige al usuario a la ruta indicada:

# default values
all:
  facebook:
    redirect_after_connect: true
    redirect_after_connect_url: '@register_with_facebook'

12.3.2. El filtro de Facebook Connect

Otra de las características importantes de Facebook Connect es que muchos de los usuarios que visitan tu sitio web ya se han conectado previamente en Facebook. Esta característica la aprovecha el plugin sfFacebookConnectRememberMeFilter de forma muy útil. Si un usuario que visita tu sitio web ya está conectado a Facebook, el plugin sfFacebookConnectRememberMeFilter le conecta de forma automática al sitio web de la misma forma en la que lo hace el filtro "Remember me".

$sfGuardUser = sfFacebook::getSfGuardUserByFacebookSession();
if ($sfGuardUser)
{
  $this->getContext()->getUser()->signIn($sfGuardUser, true);
}

Sin embargo, esta funcionalidad tiene una desventaja que puede ser importante: los usuarios no se pueden desconectar del sitio web mientras permanezcan conectados en Facebook. Por tanto, emplea esta característica con cautela.

12.3.3. Cómo evitar los errores de JavaScript en Internet Explorer

Uno de los errores más graves que pueden suceder en una aplicación web es el famoso error "Operation aborted" de Internet Explorer que impide que se muestre la aplicación web. El motivo de este error es el motor de renderizado de IE 6 y IE 7, que produce un error grave cuando se añaden elementos DOM al <body> desde un script que no sea hijo directo del <body>

Desafortunadamente esta práctica es habitual cuando cargas el código JavaScript de Facebook Connect sin preocuparte de cargarlo solamente desde el elemento <body> y desde el final de la página. Symfony puede solucionar fácilmente este problema mediante el uso de los slots. Siempre que se vaya a incluir el script de Facebook Connect, se utiliza un slot en la plantilla y se muestra al final del layout, justo antes de la etiqueta </body>:

// en una plantilla que utilice XFBML o un botón de Facebook Connect
slot('fb_connect');
include_facebook_connect_script();
end_slot();

// justo antes de la etiqueta </body> del layout
if (has_slot('fb_connect'))
{
  include_slot('fb_connect');
}