Monthly Archives: March 2013

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"
    }
}

Scaling Silex applications (part II). Using RouteCollection

In the post Scaling Silex applications I wanted to organize a one Silex application. In one comment Igor Wiedler recommended us to use RouteCollections instead of define the routes with a Symfony’s Dependency Injection Container. Because of that I started to hack a little bit about it and here I show you my outcomes:

I want to build an imaginary application with silex. This application has also one Api and one little blog. I want to organize those parts. Our index.php file

<?php
// www/index.php
require_once __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\RouteCollection;
use Silex\Application;

$app = new Application();

$app['routes'] = $app->extend('routes', function (RouteCollection $routes, Application $app) {
    $loader     = new YamlFileLoader(new FileLocator(__DIR__ . '/../config'));
    $collection = $loader->load('routes.yml');
    $routes->addCollection($collection);

    return $routes;
});

$app->run();

Now our routes.yml file:

# config/routes.yml

home:
  path: /
  defaults: { _controller: 'Gonzalo123\AppController::homeAction' }

hello:
  path: /hello/{name}
  defaults: { _controller: 'Gonzalo123\AppController::helloAction' }

api:
  prefix: /api
  resource: api.yml

blog:
  prefix: /blog
  resource: blog.yml

As we can see we have separated the main routing file into different files: api.yml (for the Api) and blog.yml (for the blog)

# config/api.yml

api.list:
  path:     /list
  defaults: { _controller: 'Gonzalo123\ApiController::listAction' }
# blog.yml

blog.home:
  path:     /
  defaults: { _controller: 'Gonzalo123\BlogController::homeAction' }

And now we can create our controllers:

<?php
// lib/Gonzalo123/AppController.php

namespace Gonzalo123;

use Symfony\Component\HttpFoundation\Response;
use Silex\Application;

class AppController
{
    public function homeAction()
    {
        return new Response("AppController::homeAction");
    }

    public function helloAction(Application $app, $name)
    {
        return new Response("Hello" . $app->escape($name));
    }
}
<?php
// lib/Gonzalo123/ApiController.php

namespace Gonzalo123;

use Symfony\Component\HttpFoundation\Response;

class ApiController
{
    public function listAction()
    {
        return new Response("AppController::listAction");
    }
}
<?php
// lib/Gonzalo123/BlogController.php

namespace Gonzalo123;

use Symfony\Component\HttpFoundation\Response;

class BlogController
{
    public function homeAction()
    {
        return new Response("BlogController::homeAction");
    }
}

And that’s all. Here also the needed dependencies within our composer.json file

{
    "require":{
        "silex/silex":"1.0.*@dev",
        "symfony/yaml":"v2.2.0",
        "symfony/config":"v2.2.0"
    },
    "autoload":{
        "psr-0":{
            "":"lib/"
        }
    }
}

source code at github.

Follow

Get every new post delivered to your Inbox.

Join 976 other followers