Autonomous Machine

Fitzgerald: a Sinatra clone in PHP

Two weeks ago I had a tiny client website that suddenly needed a login section to provide some downloads to approved users. Initially I reached for Sinatra, which I have grown to love in recent months, but sadly the client's server had no opportunity to run Ruby. A sad day for sure, but the world moves on and I decided to revisit my old friend PHP and see what could be done.

I spent about ten minutes looking through various PHP frameworks, but quickly decided that it would be faster to write the code the tiny site would need than learn the ins and outs of a full framework. I wanted something tiny anyway (preferably a single file), and most of what I found online were various fully fledged MVC Rails clones. Not going to work.

I knew I wanted a solution that would get me as close to possible to Sinatra's syntax, while making the best of the confines of PHP. Here's the final syntax I came up with:

<?php
    include('lib/fitzgerald.php');
    
    class Application extends Fitzgerald {
        
        // Basic get request
        public function get_index() {
            return $this->render('index');
        }
    }
    
    $app = new Application();
    
    $app->get('/', 'get_index');
    
    $app->run();
?>

The basic concept is to subclass Fitzgerald with controller methods, and then map them to urls using get() and post() calls on an instantiated application object.

I added some Merb-style argument passing to the mix using PHP5's Reflection API:

<?php
    include('lib/fitzgerald.php');
    
    class Application extends Fitzgerald {
        
        // $page will be one of 'about', 'contact', or 'faq' thanks to our URL mapping below
        public function get_page($page) {
            return $this->render($page);
        }
    }
    
    $app = new Application();

    // :page is a placeholder- it will match anything by default, or a regex to match can
    // be passed in using an optional third argument to get() or post()
    $app->get('/:page', 'get_page', array('page' => 'about|contact|faq'));
    
    $app->run();
?>

Like Sinatra, the return value of a method is what is returned to the browser. Fitzgerald has built in methods to render a template or redirect the browser:

<?php
    class Application extends Fitzgerald {
        
        // Renders a php file in '../views/', making variables provided to compact
        // available as local variables in the template
        public function get_page($page) {
            $var1 = 'Value to use in template';
            $var2 = 'Another value to use in template';
            return $this->render($page, compact('var1', 'var2'));
        }

        // You can also send redirect headers
        public function get_redirect {
            return $this->redirect('/url/to/redirect/to');
        }
    }
?>

You can also specify a layout with an options array passed to the application initialization:

<?php
  // This will capture the output of any render calls into a local variable $content,
  // and then render the layout provided here
  $app = new ApplicationWithLogin(array('layout' => 'shell'));
?>

And that's Fitzgerald. There is a more advanced example that shows how to build a simple authentication system in the repo on Github- look at example.php.