Sign-in with Twitter in a Silex application.

I’ve working in a pet-project with Silex and I wanted to perform a Sign-in with Twitter. Implementing Sign in with Twitter is pretty straightforward and it’s also well explained in the Twitter’s developers site. Now we only need to implement those HTTP client requests within PHP. We can create the REST client with curl but nowadays I prefer to use the great library called Guzzle to perform those kind of opperations. So let’s start.

The idea is to create something reusable. I don’t want to spend too much time including the Sign-in with Twitter in my proyects, so my first idea was to create a class with all the needed code and mount this class as group of Silex controllers (as it’s defined here). I also want to keep the class as standard as possible and avoiding the usage of any other external dependencies (except Guzzle)..

Imagine a simple Silex application:

<?php
// www/index.php
include __DIR__ . "/../vendor/autoload.php";

$app = new Silex\Application();
$app->get('/', function () {
    return 'Hello';
});

$app->run();

Now I want to use a Sign-in with Twitter, so I will change the application to:

<?php
include __DIR__ . "/../vendor/autoload.php";

$app = new Silex\Application();
$app->register(new Silex\Provider\SessionServiceProvider());

$consumerKey    = "***";
$consumerSecret = "***";

$twitterLoggin = new SilexTwitterLogin($app, 'twitter');
$twitterLoggin->setConsumerKey($consumerKey);
$twitterLoggin->setConsumerSecret($consumerSecret);
$twitterLoggin->registerOnLoggin(function () use ($app, $twitterLoggin) {
    $app['session']->set($twitterLoggin->getSessionId(), [
        'user_id'            => $twitterLoggin->getUserId(),
        'screen_name'        => $twitterLoggin->getScreenName(),
        'oauth_token'        => $twitterLoggin->getOauthToken(),
        'oauth_token_secret' => $twitterLoggin->getOauthTokenSecret()
    ]);
});

$twitterLoggin->mountOn('/login', function () {
    return '<a href="/login/requestToken">login</a>';
});

$app->get('/', function () use ($app){
    return 'Hello ' . $app['session']->get('twitter')['screen_name'];
});

$app->run();

The application will redirects all requests (without the correct session) to the route “/login”. The login page has a simple link to the route: “/login/requestToken” (we can create a fancy template with Twig if we want, indeed). This route redirects the request to Twitter’s login page and after a successful login it will redirects back to the route that we have defined within our Twitter application. The library assumes that this callback’s url is “/login/callbackUrl”. All this default routes can be defined by the user using the proper setters of the class.

When the sign-in is finished the application will trigger the callback defined in registerOnLoggin function and will redirects to the route “/”. This route (called internally “redirectOnSuccess”) is also customizable with a setter.

And that’s all. Library available at github and packagist

{
    "require": {
        "gonzalo123/silex-twitter-login": "dev-master"
    }
}
Advertisement

How to configure Symfony’s Service Container to use Twitter API

Keeping on with the series about Symfony’s Services container (another posts here and here), now we will use the service container to use Twitter API from a service.

To use Twitter API we need to handle http requests. I’ve written several post about http request with PHP (example1, example2), but today we will use one amazing library to build clients: Guzzle. Guzzle is amazing. We can easily build a Twitter client with it. There’s one example is its landing page:

<?php
$client = new Client('https://api.twitter.com/{version}', array('version' => '1.1'));
$oauth  = new OauthPlugin(array(
    'consumer_key'    => '***',
    'consumer_secret' => '***',
    'token'           => '***',
    'token_secret'    => '***'
));
$client->addSubscriber($oauth);

echo $client->get('/statuses/user_timeline.json')->send()->getBody();

If we are working within a Symfony2 application or a PHP application that uses the Symfony’s Dependency injection container component you can easily integrate this simple script in the service container. I will show you the way that I use to do it. Let’s start:

The idea is simple. First we include guzzle within our composer.json and execute composer update:

    "require": {
        "guzzle/guzzle":"dev-master"
    }

Then we will create two files, one to store our Twitter credentials and another one to configure the service container:

# twitter.conf.yml
parameters:
  twitter.baseurl: https://api.twitter.com/1.1

  twitter.config:
    consumer_key: ***
    consumer_secret: ***
    token: ***
    token_secret: ***
# twitter.yml
parameters:
  class.guzzle.response: Guzzle\Http\Message\Response
  class.guzzle.client: Guzzle\Http\Client
  class.guzzle.oauthplugin: Guzzle\Plugin\Oauth\OauthPlugin

services:
  guzzle.twitter.client:
    class: %class.guzzle.client%
    arguments: [%twitter.baseurl%]
    calls:
      - [addSubscriber, [@guzzle.twitter.oauthplugin]]

  guzzle.twitter.oauthplugin:
    class: %class.guzzle.oauthplugin%
    arguments: [%twitter.config%]

And finally we include those files in our services.yml:

# services.yml
imports:
- { resource: twitter.conf.yml }
- { resource: twitter.yml }

And that’s all. Now we can use the service without problems:

<?php

namespace Gonzalo123\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        $twitterClient = $this->container->get('guzzle.twitter.client');
        $status = $twitterClient->get('statuses/user_timeline.json')
             ->send()->getBody();

        return $this->render('AppBundle:Default:index.html.twig', array(
            'status' => $status
        ));
    }
}