Blog Tutorial with Fat-Free Framework

View the blog tutorial updated for version 3 here

I recently read an excellent tutorial on ‘Rapid Application Prototyping in PHP Using a Micro Framework‘, this used the Slim micro framework but one thing that bothered me was it required 5 packages before development could start.
These were: Slim (the micro framework), Slim Extras (additional resources for Slim), Twig (template engine), Idiorm (object-relational mapper) and Paris (Active Record implementation).
It struck me that if you need an extra 4 packages alongside Slim for a basic blog then maybe it is a little too skinny and I set out to find a micro framework that could do the same thing without these dependencies.

I found the Fat-Free Framework. It is condensed into a single 55KB file and has a host of features, you can find out about these on their web site so I won’t repeat it here. Instead I’ve reproduced the Slim tutorial to create a simple blog site, but using Fat-Free Framework instead.
You will need PHP 5.3 on your server, I used Ubuntu 11.04 for the tutorial as that version of PHP is easily installed. If you’re on RHEL or Centos then I’d suggest taking a look at the IUS Community Project for getting a recent PHP version.

Step 1: Setup

Download Fat-Free Framework (F3) from the website.
F3 works just as happily in the site root as from a subdirectory – I’ll assume you’re using a subdirectory here as it means you won’t have to set up a seperate site to do this tutorial.
Create a folder called blog and unzip the contents of the F3 download into that. It should look like this:
Move up one level in the directory heirarchy and set the permissions:

sudo chgrp -R www-data blog
sudo chmod -R 775 blog

The folder contents should look like this:
Folder Contents

Notice how much simpler the starting site is compared with Slim + extra packages.

If using Apache, mod_rewrite will need to be running. Edit .htaccess and adjust RewriteBase to add the blog subfolder that you are using, so it looks like RewriteBase /blog.

You can browse this site right away and get the F3 start page.
start page
(Once the site has been visited, F3 will create additional folders cache and temp – you don’t need to worry about these).

Step 2: Bootstrapping

As everything we need is already part of F3 you don’t need to do anything here!

You can however tidy up the site to remove the current home page and add a database connection.
Edit index.php
comment out the CACHE option and increase the DEBUG level to help while developing, then remove the only route command. It should look like this:

<?php
 
require __DIR__.'/lib/base.php';
 
//F3::set('CACHE',TRUE);
F3::set('DEBUG',3);
F3::set('UI','ui/');
 
F3::run();
 
?>

To setup a database connection add the following between the set and run commands:

F3::set('DB',
	new DB(
		'mysql:host=localhost;port=3306;dbname=YourDatabaseName',
		'YourUsername',
		'YourPassword'
	)
);

All the User Interface files will go in the ui directory, you can delete welcome.htm and style.css from here as they were just used by the default home page.

Step 3: Routing

Similar to Slim you need to tell F3 the route request method (GET, POST, PUT etc), the URI to respond to and how to respond.
Home page route:

F3::route('GET /',
	function () {
	//do something
	}
);

The anonymous function will contain the logic to populate the page.
To view a blog article:

F3::route('GET /view/@id',
	function () {
		$id = F3::get('PARAMS["id"]');
	}
);

This tells F3 to expect a URI parameter and assigns it to a PHP variable in the anonymous function.

Now the administration routes:

// Admin Home
F3::route('GET /admin',
	function () {	
	}
);
 
//Admin Add
F3::route('GET /admin/add',
	function() {
	}
);
 
//Admin Edit 
F3::route('GET /admin/edit/@id',
	function() {
		$id = F3::get('PARAMS["id"]');
	}
);
 
//Admin Add & Edit, Deal with Form Posts
F3::route('POST /admin/edit/@id','edit');
F3::route('POST /admin/add','edit');
	function edit() {
 
	}
 
//Admin Delete
F3::route('GET /admin/delete/@id',
	function() {
		$id = F3::get('PARAMS["id"]');
	}
);

Notice that we’re using the same function to process Add and Edit form posts so it isn’t anonymous but the function name is passed as a parameter to the route command.

Step 4: Models

The ORMs in Fat-Free Framework do all the hard work for you – no directories, files or code required here.
Are you beginning to see how much simpler this is compared with Slim?

Here’s the SQL that will set you up with the 2 tables necessary for this tutorial:

CREATE DATABASE `blog` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
 
USE `blog`;
 
CREATE TABLE IF NOT EXISTS `article` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `title` VARCHAR(128) NOT NULL,
  `summary` VARCHAR(128) NOT NULL,
  `content` text NOT NULL,
  `author` VARCHAR(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
INSERT INTO `article` (`id`, `timestamp`, `title`, `summary`, `content`, `author`) VALUES
(1, '2011-07-28 02:03:14', 'Hello World!', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut ', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'Mr White'),
(2, '2011-07-28 02:03:14', 'More Hello World!', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut ', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'Mr Green');
 
CREATE TABLE IF NOT EXISTS `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
INSERT INTO `user` (`id`, `name`, `password`) VALUES
  ('1', 'admin', 'password');

Step 5: Application Front End

Like this Slim tutorial we’re going to keep this simple.
Instantiate an Axon object that interacts with the users table, call the afind method to return a simple array of results, finally the set command is used which will pass the variable between MVC components. F3 calls this a framework variable.

	$article=new Axon('article');
	$articles=$article->afind();
	F3::set('articles',$articles);

You could condense the final two lines together like F3::set('articles',$article->afind()); but I’m keeping this verbose to aid readability and help you figure out how it is all working.

To use templating you need a base layout file in the ui folder called layout.html

<!DOCTYPE html>
<html>
   <head>
      <title>{{@html_title}}</title>
      <meta charset='utf8' />
   </head>
   <body>
      <F3:include href="{{@content}}"/>
   </body>
</html>

The F3 template engine uses {{@name}} to write out the value of a framework variable.
The F3:include directive will embed the contents of a file at the position where the directive is stated – in the example above we’re using a framework variable as the URL so that the content is dynamic.

Now lets create the first of those content files with the view for the homepage, called blog_home.html

<p>Blog Titles</p>
<F3:repeat group="{{@list}}" value="{{@item}}">
	<p><a href="view/{{@item['id']}}">{{trim(@item['title'])}}</a> by {{@item['author']}}</p>
	<p>{{@item['summary']}}</p>
</F3:repeat>

The F3:repeat directive will loop through an array, setting item to the current array element. Within the loop item contains the array of data retrived from the database table and this is accessed using the column name as the array key.

Now that the view is in place we can complete the code in index.php to display it. Set the framework variable to tell the template which view to include, then tell F3 to serve the template.

	F3::set('content','blog_home.html');
	echo Template::serve('layout.html');

Serving the template also converts it to PHP code the first time it’s used and this optimised version is used thereafter which is great for performance.
The full code for this is:

F3::route('GET /',
	function () {
		F3::set('html_title','Home Page');
		$article=new Axon('article');
		F3::set('list',$article->afind());
		F3::set('content','blog_home.html');
		echo Template::serve('layout.html');	
	}
);

Now for the detail view, in index.php we need to get an Axon object, search for the id then send the data to the view/template. In this case we could have assigned each value individually e.g. F3::set('title',$article->title); but it is quicker to put all the values in the POST framework variable with the copyTo command.

F3::route('GET /view/@id',
	function () {
		$id = F3::get('PARAMS["id"]');
		//create Axon object and search for id
		$article=new Axon('article');
		$article->load("id='$id'");
		//set framework variables
		F3::set('html_title',$article->title);
		$article->copyTo('POST');
		//serve up the view
		F3::set('content','blog_detail.html');
		echo Template::serve('layout.html');
	}
);

And the view file itself called blog_detail.html accesses the individual data items from the POST framework variable:

<h1>{{@POST.title}}</h1>
<p>Published: {{@POST.timestamp}} by {{@POST.author}}</p>
{{@POST.content}}
<p><a href='../'>Back to Homepage</a></p>

Step 6: Application Back End

The admin home page just needs to list the blog articles and provide links, the code is similar to that for the homepage.

F3::route('GET /admin',
	function () {
		F3::set('html_title','My Blog Administration');
		$article=new Axon('article');
		$list=$article->afind();
		F3::set('list',$list);
		F3::set('content','admin_home.html');
		echo Template::serve('layout.html');	
	}
);

The view called admin_home.html and contains a table of the results. It looks like this:

<h1>My Blog Administration</h1>
<p><a href='admin/add'>Add Article</a></p>
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Date</th>
      <th>Author</th>
      <th colspan='2'>Actions</th>
    </tr>
  </thead>
  <tbody>
  <F3:repeat group="{{@list}}" value="{{@item}}">
    <tr>
      <td>{{@item['title']}}</td>
      <td>{{@item['timestamp']}}</td>
      <td>{{@item['author']}}</td>
      <td><a href="admin/edit/{{@item['id']}}">Edit</a></td>
      <td><a href="admin/delete/{{@item['id']}}">Delete</a></td>
    </tr>
  </F3:repeat>
  </tbody>
</table>

The output of this look like:
Admin Home Page
Now a form to add and edit articles, called admin_edit.html

<h1>Edit</h1>
<form name="blog" method="post" action="{{ @BASE }}{{ @PARAMS.0 }}" >
  <F3:check if="{{ @message }}">
    <p><span class="fail">{{ @message }}</span></p>
  </F3:check>
  <label for='title'>Title: </label><br /><input type="text" name="title" id="title" value="{{ htmlspecialchars(@POST.title) }}" size="60"/><br />
  <label for='author'>Author: </label><br /><input type="text" name="author" id="author" value="{{ htmlspecialchars(@POST.author) }}" size="60"/><br />
  <label for='summary'>Summary: </label><br /><textarea name="summary" id="summary" cols="60" rows="10">{{ htmlspecialchars(@POST.summary) }}</textarea><br />
  <label for='content'>Content: </label><br /><textarea name="content" id="content" cols="60" rows="10">{{ htmlspecialchars(@POST.content) }}</textarea><br />
  <input type="submit" value="Submit"/>
</form>

I’ve kept this basic, apologies for the lack of styling but that’s not what this tutorial is about.
Note that there’s an area to display validation messages.

Now for the logic with the routes, add & edit both use the same view remember.

F3::route('GET /admin/add',
	function() {
		F3::set('html_title','My Blog Create');
		F3::set('content','admin_edit.html');
		echo Template::serve('layout.html');
	}
);
 
F3::route('GET /admin/edit/@id',
	function() {
		F3::set('html_title','My Blog Edit');
		$id = F3::get('PARAMS["id"]');
		$article=new Axon('article');
		$article->load("id='$id'");
		$article->copyTo('POST');
		F3::set('content','admin_edit.html');
		echo Template::serve('layout.html');
	}
);

Now we assigned a function for the POST routes and here’s the content:

	function edit() {
		// Reset previous error message, if any
		F3::clear('message');
		$id = F3::get('PARAMS["id"]');
		$article=new Axon('article');
		//load in the article, set new values then save
		//if we don't load it first Axon will do an insert instead of update when we use save command
		if ($id) $article->load("id='$id'");
		//overwrite with values just submitted
		$article->copyFrom('POST');
		//create a timestamp in MySQL format
		$article->timestamp=date("Y-m-d H:i:s");
		$article->save();
		// Return to admin home page, new blog entry should now be there
		F3::reroute('/admin');
	}

There’s a lot less coding required here than with Slim + extras.

Step 7: Using Middleware

This isn’t relevant to using the Fat-Free Framework.
Authentication using a database is built in so I’ll step through how to use it.
The following lines are added to the admin homepage route

//tell F3 the database table and fields for user id and password
F3::set('AUTH',array('table'=>'user','id'=>'name','pw'=>'password'));
//carry out authentication
$auth = Auth::basic('sql');
//if successful, set a framework variable
if ($auth) {
  //set the session so user stays logged in
  F3::set('SESSION.user',$auth->name);
  //display the admin view
  F3::set('content','admin_home.html');
} else {
  //login unsuccessful so display message
	F3::set('content','security.html');
}

security.html looks like this:

<p>You must supply valid login details.</p>

In the add & edit routes, add this line before Template::serve

if (!F3::get('SESSION.user')) F3::set('content','security.html');

That’s it (if you didn’t spot it in the SQL, my example uses admin & password for the login credentials).
I did get a bug with version 2.0.5, auth.php line 230 if you get this then that line should read self::HTTP_WebAuth instead of HTTP_WebAuth on its own.

You could instead choose to redirect back to the homepage with:

if (!F3::get('SESSION.user')) F3::reroute('/');

This would also work in the start of delete and POST routes and may make the application more secure, security.html wouldn’t be required.

Step 8: Summary

So here is another example of how to quickly get a prototype running using a PHP micro framework.
Is it any faster than with Slim? I’d like to think that it is, there’s less code, less complexity and you aren’t dependent on other packages which may end up changing in some way or not being maintained.
I’ve used F3 to create a times tables application for my son and found it was fun to build and made me more productive – I’ve now put it online at times-tables.willis-owen.co.uk for anyone to use.

I should add that Licensing of Fat-Free Framework means for academic and personal use it uses the GNU General Public License and is free, however for business or commercial gain you need to contact the developers.
Slim is released under the MIT Public License and you are free to use, modify and even sell it.

You can download the files used from here blog.zip.

I’ve done another tutorial on creating a near identical blog application to this but using CakePHP: Blog Tutorial with CakePHP Framework which may be interesting to compare with differences with using a micro-framework.

This entry was posted in MySQL, PHP. Bookmark the permalink.

23 Responses to Blog Tutorial with Fat-Free Framework

  1. Mitali says:

    Hey can you please provide download link for this demo project?

  2. Jamie says:

    Great tutorial. I actually mentioned a bunch of alternative micro frameworks in my original tutorial copy, which included F3 (I’ve used it before), but it seems to have been cut from the final tutorial.

    From my perspective I prefer to use components I feel are best suited to each particular task, which is why I prefer Paris over Axon and Twig over F3′s solution. But I guess this always come down to personal preference.

    Both Twig and Slim have active development cycles, and Twig is a core component of Symfony2, which gives me confidence in using it heavily. Slim also recently added a route mapping feature, which means you can respond to multiple request methods with the same closure, which would have made my tutorial a bit more concise.

  3. Michael says:

    Thanks so much for putting this article up… very interesting to see the comparison of the two micro frameworks.

    Having both frameworks (f3 and Slim) up on the same machine (vmware mint 11 installation, 2gb, 1 core allotted, phenom 2) I ran apache benchmark (ab) against both of the versions.

    Slim
    $ ab -n 10 -c 5 http://localhost/slim-tut/
    Requests per second: 0.33 [#/sec] (mean)

    Fatfree
    $ ab -n 10 -c 5 http://localhost/f3/blog/
    Requests per second: 25.45 [#/sec] (mean)

    Quite a difference.

    Additionally, f3′s flat file orm (jig) looks quite handy for very lightweight apps not needing a DB .

    These days I’m mostly using yii, but for occasions where yii is a bit overkill, i’ll likely have a go with f3.

  4. Pingback: PHP Fat-Free Framework « TuxAdmin

  5. Riefvan says:

    Hi,

    Great tutorial. IMO it has easier examples than one in the official F3 documentation.

    Anyway, i think there’s an error in admin_home.html line 2. Whenever i click “Add article” i got “The URL /blog/admin/edit was not found”.
    I did this to fix it.
    Replace:
    Add Article
    with:
    Add Article

  6. EllisGL says:

    I’ve noticed a bug with the auth. If you mess up the login, refresh, it automatically gives the “error” message. Close out of the browser to kill the session and you can login.

  7. Paul says:

    Thanks for this great article.

    I’ve been using Yii for a while and feel it is overkill for smaller sites. I just became aware of F3 and this blog example looks like the perfect way to create something meaningful from scratch as a way to get to know the framework. I like the idea of a light-weight frame work that contains all the essentials without the bloat. I arrived here from the Slim, Twig, Paris, etc blog tute and agree using F3 is the way to go if it does it all without any bloat. Thanks for sharing!

  8. Khanh Nguyen says:

    @blog_detail.html: I’d like to print out $_POST. Normally I use
    <?php
    echo '';
    print_r($_POST);
    echo '';
    ?>
    .
    I add this code in blog_detail.html but get no output in my browser. Any suggestions? Tks.

  9. Carsten says:

    I recently re-build a website with CI and with that experience fresh in mind I wanted to try out F3 after reading this article and other good reviews around the net.

    Getting everything working wasn’t too hard, even though from time to time I ran in to various problems requiring a google search. Getting answers was noticeable harder than with CI – the onepage F3 website isn’t exactly thorough.

    Never the less, F3 was indeed not hard to use, but my biggest concern is speed. I tried both the DB method as well as Axon and when using DB my site spent around 0.2-0.3 s to display while using Axon would increase this to no less than 3-4 s.

    I thought about it and decided to revert to CI to see the comparison and much to my surprise, CI clocked in at around 0.03 – 0.1 s for exactly the same tasks.

    Any ideas why F3 seemingly is much slower than CI – I would have expected the reverse result more or less.

    Btw. very good article.

  10. jayson says:

    good tutorial

  11. Darmanto.com says:

    komplit banget tutorialnya…

  12. Mike says:

    Any chance you could update this? Axon has been removed and I’m having trouble trying to get this tutorial up and running.

  13. Paulo says:

    Please update your post. The new version of F3 no longer uses the Axon.

  14. Naomi says:

    If some one wishes expert view on the topic of blogging and site-building
    afterward i advise him/her to visit this web site, Keep up
    the good work.

  15. Thanks for this tutorial Richard. However, not only is the Axon no longer used,
    also the auth mechanism seems to have changed. However, the official github documentation doesn’t state anything about authenticating. impossible to find concrete information about how to authenticate using fat free framework.

  16. Anonymous says:

    Good tutorial! Thanks.

    The only thing preventing me to try fat free is the license.

    Does the license allow commercial usage? It’s not quite clear.

    Slim has a more liberal license.

Leave a Reply

Your email address will not be published. Required fields are marked *


7 × = 7

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>