Out of Mind

Do less, and then do even less

November 10, 2010 at 9:32am

Minium: Simple Example of Lithium as a Microframework

My post yesterday has been viewed 362 times. Wow, I’m not expecting that. Most of visitors came from Reddit (thanks Reddit!) and twitter (great!). As a present to you all, I has made a simple example of how to use Lithium as a microframework.

I called it minium. It only contains four file: .htaccess, index.php, routes.php, and filters.php. A .htaccess will redirect all request to index.php as a front controller. routes.php and filters.php contains routes and filters from my previous example.

index.php is an example of how to run Lithium with minimum requirement. Just include lithium\core\Libraries and run lithium\action\Dispatcher and you are done. That’s how awesome Lithium are. You can grab minium in github repository. I welcome any feedback.

November 9, 2010 at 9:43am

Lithify It Like Sinatra

Lithium, the awesome php framework nearly released it’s 1.0 version. One of the awesomness of Lithium is it’s flexibility. It’s very flexible so you can use it as a Sinatra equivalent in PHP. Let’s take a look.

RESTful Routing

Lithium can do RESTful routing like this:

// GET request
Router::connect("/create", array("http:method" => "GET"),
    function($request){
        // Do something and return Response object
    }
);

// POST request
Router::connect("/create", array("http:method" => "POST"),
    function($request){
        // Do something and return Response object
    }
);

// PUT request
Router::connect("/create", array("http:method" => "PUT"),
    function($request){
        // Do something and return Response object
    }
);

// DELETE request
Router::connect("/create", array("http:method" => "DELETE"),
    function($request){
        // Do something and return Response object
    }
);

// Allow POST or PUT::
Router::connect("/update", array("http:method" => array("POST", "PUT")),
    function($request){
        // Do something and return Response object
    }
);

You can also use named parameters which accessible via $request.

Router::connect("/hello/{:name}", array("http:method" => "GET", "name" => null),
    function($request) {
        $name = $request->name ?: 'World';
        return new Response(array('body' => "Hello {$name}!"));
    }
);

Finally you can also use pattern:

Router::connect('/user/{:id:[0-9]+}', array("http:method" => "GET"),
    function($request) {
        $id = $request->id ?: 0;
        return new Response(array('body' => "Id: {$id}"));
    }
);

Conditional Routing

In lithium, you can access all properties of request object. This allow you to do conditional routing (in fact, RESTful routing are conditional routing).

// Only match if on the dev server and GET request:
Router::connect("/secret", array("http:method" => "GET", "http:host" => "dev.application.com"),
    function($request){
        // Do something and return Response object
    }
);

// Only match if request is over HTTPS and GET request:
Router::connect("/admin", array("http:method" => "GET", "env:https" => true),
    function($request){
        // Do something and return Response object
    }
);

Passing

You can punt processing to the next matching route by returning false.

// If $name is not jamal, pass it to next route
Router::connect("/guess/{:name}", array("http:method" => "GET"),
    function($request){
        $name = $request->name;
        if($name == 'jamal') {
            return new Response(array('body' => "You can guess my name.!"));
        }
        return false;
    }
);


// Match every access to /guess/*
Router::connect("/guess/{:name}", array("http:method" => "GET"),
    function($request){
        return new Response(array('body' => "Try again!"));
    }
);

Filters

Man, filters in Lithium are awesome. You can filter almost everything.

use lithium\action\Dispatcher;

// Filter all request
Dispatcher::applyFilter('run', function($self, $params, $chain) {
    // Do something before
    $result = $chain->next($self, $params, $chain);
    // Do something after
    return $result;
});

// Filter GET request
Dispatcher::applyFilter('run', function($self, $params, $chain) {
    if($params['request']->method == 'GET') {
        // Do something before
    }
    $result = $chain->next($self, $params, $chain);
    if($params['request']->method == 'GET') {
        // Do something after
    }
    return $result;
});

// Protect some routes from unauthorized user
use lithium\action\Dispatcher;
use lithium\net\http\Router;
use lithium\action\Response;
use lithium\security\Auth;

Dispatcher::applyFilter('run', function($self, $params, $chain) {
    // First, define our list of protected actions
    $blacklist = array(
        '/users/report',
        '/users/home'
    );

    // Inspect the request to get the URL for the route the request matches
    $matches = in_array(Router::match($params['request']->params, $params['request']), $blacklist);

    // If this is a match, check it against an Auth configuration.
    if($matches && !Auth::check('default', $params['request'])) {
        // If the Auth check can't verify the user, redirect.
        return new Response(array('location' => '/users/login'));
    }

    // Important: return the results of the next filter in the chain.
    return $chain->next($self, $params, $chain);
});

Thats it. I’m out of gas.

Update 1: Fix error in named parameter and passing example.

Update 2: I have created a simple example. Read about it here.

July 22, 2010 at 5:10pm

‘Try again. Fail again. Fail better.’ ~Samuel Beckett

July 14, 2010 at 12:45pm

So Many To Do…

…so little time i have. I want to follow Zen Habits idea: ‘do less and then do even less’.