Rapid Application Prototyping in PHP Using a Micro Framework

Rapid Application Prototyping in PHP Using a Micro Framework

Tutorial Details
  • Program: PHP
  • Version: 5.3
  • Difficulty: Medium
  • Estimated Completion Time: 30 Minutes

Let’s face it: we all have great ideas for a web application. Whether you write them down on paper or remember them using your eidetic memory, there comes a point when you want test whether or not your idea is really viable.

In this tutorial, we’ll use a micro framework, a templating language and an ORM to rapidly develop an application prototype.


Step 1: Introduction and Setup

We’ve all had that feeling. You know, the one where you know you have a great web application idea, only you don’t have the time to whip up a quick prototype and test the idea will truly work. Using a micro framework, a templating language and an ORM, you could have it up and running in minutes.

For this tutorial, we’ll be using the excellent micro framework Slim, the templating language Twig and the lightweight fluent ORM Paris and Idiorm. Our sample application will be a blog. You’ve probably built a blog before, but we’re here to learn about micro frameworks, and a blog fits the bill nicely!

The first thing you’ll want to do is grab these packages from their respective websites:

Now that you have all the packages downloaded to your computer, it’s time to setup your directory structure. We’ll be putting the files into our site root folder, so your project folder should look like so:

Our prototype directory structure

“Don’t forget to include the .htaccess file that comes with Slim.”

Now that we’ve got our project structured, go ahead and delete the contents of the Slim index.php file — we’ll write our own a little later on. You can also scrap everything but the TwigView.php class file in the Slim extras package.


Step 2: Bootstrapping

Our index.php file will act as a bootstrap, which will get Slim, Twig and Paris and Idiorm all working together nicely. Slim will redirect all requests to our application here, checking for any matching route patterns and then dispatching the appropriate response. This file will eventually contain our entire application setup and logic.

The first thing we need to do is include all the libraries that will make the magic happen. Add the following to the index.php bootstrap file:

	<?php
	// Slim
	require 'Slim/Slim.php';
	require 'Views/TwigView.php';

	// Paris and Idiorm
	require 'Paris/idiorm.php';
	require 'Paris/paris.php';

If all goes well, a request to your application should do absolutely nothing, which is great!

Now let’s get Twig up and running. Using the Slim extras package we can let Slim setup a Twig environment for us. All it needs to know is the directory Twig is in, so let’s add that into our bootstrap. Also go ahead and create a templates directory named templates in the site root while you are at it.

	// Configuration
	TwigView::$twigDirectory = __DIR__ . '/Twig/lib/Twig/';

The next component in our stack is Paris and Idiorm, our ORM. It utilises the inbuilt PHP PDO object, so you could use Postgres or SQLite for your prototype, but for this tutorial we’ll be using MySQL. Be sure to give it the appropriate database credentials:

	ORM::configure('mysql:host=localhost;dbname=blog');
	ORM::configure('username', 'root');
	ORM::configure('password', '');

Finally, let’s get Slim up and running. It’s quite complicated, I think you’ll agree:

	// Start Slim.
	$app = new Slim(array(
		'view' => new TwigView
	));

A word of warning. If you try run your application now, you may get a cryptic error. Don’t panic! We’ll resolve that in just a moment by adding some routes.


Step 3: Routing

Adding routes in Slim is simple. All Slim needs to know is the route request method (E.g. GET, POST, PUT etc) and URI to respond to, and how to respond. We’ll flesh out the basic routes of our application first and create the guts of the prototype further on in this tutorial.

Let’s create a homepage route first:

	// Blog Home.
	$app->get('/', function() use ($app) {

	});

Here we’re telling Slim to respond to any GET request pointed to the root of our app. The final closure parameter will eventually contain the logic to generate the page output.

Let’s add another route for viewing an individual blog article:

	// Blog View.
	$app->get('/view/(:id)', function($id) use ($app) {

	});

Notice the difference here? In our URI parameter, we’ve added a slug (:id), which tells Slim to expect a value at the end of the URI.

If you’ve ever used any other PHP framework, you’re probably familiar with this concept. If you’re not, our example would match /view/1, /view/2 etc.

We’ve also passed this parameter to our closure function, so we can use it in our application logic as well. Notice how we’ve also passed in our application variable into the closures scope, with the use statement? This allows us to access the internals of Slim, which we’ll be using to grab request data and render responses.

Our administration routes will need to use different request methods, so let’s add them in:

	// Admin Home.
	$app->get('/admin', function() use ($app) {

	});

	// Admin Add.
	$app->get('/admin/add', function() use ($app) {

	});	
	
	// Admin Add - POST.
	$app->post('/admin/add', function() use ($app) {

	});

	// Admin Edit.
	$app->get('/admin/edit/(:id)', function($id) use ($app) {

	});

	// Admin Edit - POST.
	$app->post('/admin/edit/(:id)', function($id) use ($app) {

	});

	// Admin Delete.
	$app->get('/admin/delete/(:id)', function($id) use ($app) {

	});

You’ll notice that we’ve got some POST routes in here. Later, we’ll use these to process forms in our admin centre.

Finally, we’d better tell Slim to run our application.

	$app->run();

Step 4: Models

Paris and Idiorm makes building models to represent your data easy as it does most of the grunt work, which is great for quick prototyping. We’ll store our models in a directory named models, so go ahead and create that directory. Inside it, create the basic Article model in a file called Article.php:

	<?php
	class Article extends Model
	{
	
	}

Pretty simple, huh? Paris and Idiorm will extract all the information it needs from the model class name and the database table. While we’re at it, we should probably create the database and add in some sample data:

	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');	

Lastly, as we’ll be using the Article model in every page, we’ll include it in our bootstrap, just after where we loaded our libraries:

	// Models
	require 'models/Article.php';

Step 5: Application Front End

Now that we’ve got our application routes all laid out, and our models configured, it’s time to start building some pages. Our blog front end is going to be pretty simple, with a list of all blog articles and a page to view individual articles.

Using the chainable fluent interface Paris and Idiorm provide, we can quickly construct database queries, without writing any raw SQL. Let’s pull out all the articles for the homepage using the route closure:

	$articles = Model::factory('Article')->order_by_desc('timestamp')->find_many();

We start by calling the model factory method, which will dispense a model object of the type Article. From here, we have a fluent interface, which means we can chain our commands together. Here, we’re getting all the articles in the database, ordered by their timestamp, in descending order, and then telling Paris we want many articles returned. The result of this query is an array of Article model objects.

In order to get our results to show up in the browser, we need to render a template. Slim provides a simple render method to do this. The first parameter is the template to render, and the second parameter is an associative array of data to be made available to the template, which in our case is our article objects.

	return $app->render('blog_home.html', array('articles' => $articles));

We’ll be writing our templates using Twig, which provides a clean and simple tag structure with inheritance features that we can use to easily layout a webpage without using any PHP. This is great for prototyping, as it means focusing on shaping the page output, instead of wading through intermingled PHP and HTML spaghetti code.

We need a base layout file — a basic HTML file in your templates folder called layout.html will do.

	<!DOCTYPE html>
	<html>
		<head>
			<title>{% block page_title %} {% endblock %}</title>
			<meta charset=&quot;utf8&quot; />
		</head>
		<body>
			{% block content %} {% endblock %}
		</body>
	</html>

Notice the Twig block tags? Blocks are named regions that you can populate with content. We’ll populate these blocks in our individual page templates.

Here’s a quick crash course on Twig to get you going.

Any variable or expression within {{ }} is automatically escaped and echoed, whilst the {% %} tags allow you to use execute statements such as if else conditionals or for loops.

Let’s walk though creating the blog homepage template step by step. Don’t forget to create a new template called blog_home.html in your templates folder.

The first thing we want our template to do is extend our layout. The extends tag lets Twig know our template will be inheriting from the layout.html file:

	{% extends 'layout.html' %}

Now, we can use the same block syntax we used earlier to populate our layout. Let’s set the page title:

	{% block page_title %}My Blog{% endblock %}

Twig will populate the page_title region in the layout, with what we defined in our template. To illustrate the power of Twig further, let’s create the content block, and use a few more Twig features:

	{% block content %}
		{% for article in articles %}
			
		{% else %}	
			<p>There are currently no articles.</p>
		{% endif %}
	{% endblock %}

Remember we passed our retrieved articles array to our template earlier on? This is now available in the template with the name articles. Using Twigs logic tags, we loop through the articles variable to check whether it exists and if it doesn’t, we put out a polite warning message. We consolidate a for loop and else conditional into one set of tags to easily handle an empty array.

Let’s display a list of blog articles on the homepage to get ourselves familiar with Twig’s looping and variable output syntax:

	{% block content %}
		{% for article in articles %}
			<h1><a href=&quot;/view/{{ article.id }}&quot;>{{ article.title }}</a> by {{ article.author }}</h1>
			<p>{{ article.summary }}</p>
		{% else %}	
			<p>There are currently no articles.</p>
		{% endfor %}
	{% endblock %}

The for loop syntax is the reverse of PHP’s foreach statement — we merely use the keyword in, instead of as. This loops through our array of article objects, making each available as a variable called article within the loop.

Inside the loop, we use the {{ }} tags, which will echo out an escaped value. Yes, Twig automatically escapes your output, so no more writing htmlentities()! We also access our articles title attribute using a dot (.) notation, instead of the usual PHP arrow (->). If you’ve written Javascript or Python, you should be familiar with some of this syntax.

Our basic homepage appearance

So now that we have our basic homepage laid out, let’s get cracking on that detail view.

	// Blog View.
	$app->get('/view/(:id)', function($id) use ($app) {
		$article = Model::factory('Article')->find_one($id);
		if (! $article instanceof Article) {
			$app->notFound();
		}

		return $app->render('blog_detail.html', array('article' => $article));
	});	

Using Paris, we can quickly grab an article by its ID using the find_one() method. If no Article object instance is returned, we tell the Slim application that the page was not found, which will automatically trigger a 404 error.

If the article is found, we pass it to our detail template, which looks as follows:

	{% extends &#x27;layout.html&#x27; %}

	{% block page_title %}{{ article.title }}{% endblock %}

	{% block content %}
		<h1>{{ article.title }}</h1>
		<p>Published: {{ article.timestamp|date(&#x27;jS F Y&#x27;) }} by {{ article.author }}</p>
		<p>{{ article.content }}</p>
		<p><a href=&quot;/&quot;>Back to Homepage</a></p>
	{% endblock %}

Using Twigs built in filters, we can access some basic PHP functions, such as date() in our templates. The class attribute article.timestamp is automatically given to our date filter as the first parameter, and our date format string becomes the second parameter.

Our basic blog detail page

We now have a front end working, albeit a simple one, but it didn’t long to get it up and running. Paris makes it really easy to focus on pulling your data out of the database, and as we’ll see when creating our admin centre, it makes it easy to insert and update records as well.


Step 6: Application Back End

Let’s work on an admin centre for our blog, which we’ll structure under the URI /admin. Seeing as we already have all the routes setup, let’s write the logic for the main admin centre page. It will be identical to our main blog listing page, so the code below should make complete sense:

	// Admin Home.
	$app->get(&#x27;/admin&#x27;, function() use ($app) {
		$articles = Model::factory(&#x27;Article&#x27;)
						->order_by_desc(&#x27;timestamp&#x27;)
						->find_many();

		return $app->render(&#x27;admin_home.html&#x27;, array(&#x27;articles&#x27; => $articles));
	});

We’ll use a simple table layout that has action links for adding, editing and deleting blog articles.

You’re already familiar with how the block region system in Twig works, so let’s just focus on our content block:

	{% block content %}	
		<h1>My Blog Administration</h1>

		<p><a href=&quot;/admin/add&quot;>Add Article</a></p>

		{% if articles %}
			<table>
				<thead>
					<tr>
						<th>Title</th>
						<th>Date</th>
						<th>Author</th>
						<th colspan=&quot;2&quot;>Actions</th>
					</tr>
				</thead>
				<tbody>

					{% for article in articles %}
						<tr>
							<td>{{ article.title }}</td>
							<td>{{ article.author }}</td>
							<td>{{ article.timestamp|date(&#x27;jS F Y&#x27;) }}</td>
							<td><a href=&quot;/admin/edit/{{ article.id }}&quot;>Edit</a></td>
							<td><a href=&quot;/admin/delete/{{ article.id }}&quot;>Delete</a></td>
						</tr>
					{% endfor %}
				</tbody>
			</table>
		{% else %}
			<p>There are currently no articles.</p>
		{% endif %}
	{% endblock %}	

In this template, we’re using the {% if %} {% else %} {% endif %} logic. We don’t want to display our table markup if there are no articles, so we check for its existence before we decide what to display. We are also using the date filter method again, which I think you’ll agree is pretty clean and legible.

Our main admin page

The Main Admin Centre

Let’s move onto the real meat of our admin centre: manipulating content. What we need is a form that contains all the fields we’ll need to add and edit our article. Luckily Twig supports reusable partials, so let’s create a form partial called article_form.html:

	<form action=&quot;{{ action_url }}&quot; method=&quot;post&quot;>
		<h1>{{ action_name }} Article</h1>

		<p>
			<label for=&quot;title&quot;>Title: </label><br />
			<input type=&quot;text&quot; name=&quot;title&quot; value=&quot;{{ article.title|default(&#x27;&#x27;) }}&quot; id=&quot;title&quot; />
		</p>

		<p>
			<label for=&quot;author&quot;>Author: </label><br />
			<input type=&quot;text&quot; name=&quot;author&quot; value=&quot;{{ article.author|default(&#x27;&#x27;) }}&quot; id=&quot;author&quot; />
		</p>

		<p>
			<label for=&quot;summary&quot;>Summary: </label><br />
			<textarea name=&quot;summary&quot; id=&quot;summary&quot; rows=&quot;10&quot; cols=&quot;20&quot;>{{ article.summary|default(&#x27;&#x27;) }}</textarea>
		</p>	

		<p>
			<label for=&quot;content&quot;>Content: </label><br />
			<textarea name=&quot;content&quot; id=&quot;content&quot; rows=&quot;10&quot; cols=&quot;20&quot;>{{ article.content|default(&#x27;&#x27;) }}</textarea>
		</p>

		<p>
			<input type=&quot;submit&quot; value=&quot;{{ action_name }} Article&quot; />
		</p>
	</form>

A partial is simply a reusable template, it can still contain standard Twig logic. In our form template, we use the default filter, which outputs a default value if the variable it is filtering is empty or non-existent. In the case of our form fields, we’ll output an empty string if none of the article attributes are present. We’re also expecting two variables to get our form partial up and running. The first called action_name simply describes the form action for our users (I.e. Add or Edit) and the second action_url is used as the form action.

You’ll no doubt have noticed how the logic for this page is split into two routes, one for GET and one for POST, which means we’ll need to write a function to handle each method. Our GET route just needs to render out the page — nothing too tricky. We’ll just tell Twig to render a new template:

	// Admin Add.
	$app->get('/admin/edit/(:id)', function($id) {
		return $app->render('admin_input.html', array('action_name' => 'Add', 'action_url' => '/admin/add'));
	});

We pass the two variables expected by our form partial into the template. Speaking of which, let me explain how to use the partial in our admin_input.html template:

	{% include 'article_form.html' %}

I’m sure you probably guessed it would be that simple, and it really is. We just need to include the partial inside one of our Twig block regions, and then it will appear. It will also have access to all variables within the scope of its main template (I.e. the two variables we passed in). Twig has some great variable scope controls and sandboxing security features, but they’re best saved for another day.

Our final input template is pretty simple (see below) and will work well when we build our edit controls too. I suppose you’re wondering why we bothered with a partial in the first palce, if both our add and edit forms will utilise the same template. The reason is because it makes reusing the form elsewhere during prototyping a real breeze to do, should it become necessary.

	{% extends 'layout.html' %}

	{% block page_title %}{{ action_name }} Article{% endblock %}

	{% block content %}
		{% include 'article_form.html' %}
	{% endblock %}
Our admin add article page

Add an Article Form

Let’s work on that POST route. What we need to do is grab the posted data, and store it inside an article object. We don’t bother with error checking in our example since we’re only roughly prototyping our idea. We’ll get Paris to dispense, or create, a new article object:

	$article = Model::factory('Article')->create();

We can now go ahead with populating the article from the posted data. We’ll grab the POST data from our Slim application object, which provides a handy helper method via its request object:

	$article->title 	= $app->request()->post('title');
	$article->author 	= $app->request()->post('author');
	$article->summary 	= $app->request()->post('summary');
	$article->content 	= $app->request()->post('content');	
	$article->timestamp = date('Y-m-d H:i:s');

Paris takes care of escaping all our input when saving, which is handy should you ever decide to stage your prototype for others to access. All we need to do now is tell Paris to save the record.

	$article->save();

Finally we tell our Slim application to take us back to the main admin dashboard page using the redirect helper method:

	$app->redirect('/admin');

Onto our edit route GET method, which is simply an amalgamation of the things we’ve learnt from building our blog detail page and our admin add page. First, we need to load up the article we are editing, by retrieving the record with Paris:

	$article = Model::factory('Article')->find_one($id);
	if (! $article instanceof Article) {
		$app->notFound();
	}

Paris dispatches an an article object instance matching the article record ID received in our closure, or false if none exists. We then check to see if we got an instance back, if not we tell Slim to throw a 404 error.

We now tell Slim to render the input template, like in our add route, but passing in the loaded article object and the correct action URL:

	return $app->render('admin_input.html', array(
		'action_name' 	=> 	'Edit', 
		'action_url' 	=> 	'/admin/edit/' . $id,
		'article'		=> 	$article
	));

Our POST edit route works almost identical to the add route, with the exception that we need to check if the article could be loaded before we go ahead and update its attributes:

	$article = Model::factory('Article')->find_one($id);
	if (! $article instanceof Article) {
		$app->notFound();
	}
	
	$article->title 	= $app->request()->post('title');
	$article->author 	= $app->request()->post('author');
	$article->summary 	= $app->request()->post('summary');
	$article->content 	= $app->request()->post('content');
	$article->timestamp = date('Y-m-d H:i:s');
	$article->save();
	
	$app->redirect('/admin');

We’ll conclude our admin centre by building the delete route. We’ll do this by first retrieving the record, similar to how we did on our blog detail page earlier on:

	$article = Model::factory('Article')->find_one($id);

If Paris loaded an article, we need to delete it, then send the user back to the main admin page. Paris makes deleting a record as simple as can be:

	if ($article instanceof Article) {
		$article->delete();
	}
	
	$app->redirect('/admin');

And with that our basic prototype admin centre is done.


Step 7: Using Middleware

Our admin centre is now completed. It’s pretty basic since it’s only a prototype, but we still want some form of authorisation on it to protect it from prying eyes. Slim allows us to insert middleware into our routes. What this means is that we can create functions that get called before our routes response closure does.

We can use HTTP Basic Auth to protect our admin centre. Obviously, we’d be using something a little more secure in a live site, but for our prototype this is fine. At the very top of our index.php let’s create two constants that contain our username and password:

	// Auth Details.
	define('USERNAME', 'admin');
	define('PASSWORD', 'password');

After we created our Slim application instance, we’ll create a closure, which we’ll bind to a variable to hold our authorisation middleware check:

	// Auth Check.
	$authCheck = function() use ($app) {

	};

If you’ve never used HTTP Basic Auth in PHP before, it’s real easy. We can use the $_SERVER array to check what credentials were sent from the user’s web browser, and compare them against our constants. We’ll do this inside our newly created closure. The first thing we need to do in our auth check function is find out if any auth credentials were sent, and if they were, check to see if they match our constants:

	$authRequest = isset($_SERVER[&#x27;PHP_AUTH_USER&#x27;], $_SERVER[&#x27;PHP_AUTH_PW&#x27;]);
	$authUser 	= $authRequest &amp;&amp; $_SERVER[&#x27;PHP_AUTH_USER&#x27;] === USERNAME;
	$authPass 	= $authRequest &amp;&amp; $_SERVER[&#x27;PHP_AUTH_PW&#x27;] === PASSWORD;

All we are doing here is checking whether the auth values exist and match, then storing the results in some variables. Assuming any of these variables is false, we know we need to prompt the user to authorize themselves:

	if (! $authUser || ! $authPass) {
		$app->response()->header(&#x27;WWW-Authenticate: Basic realm=&quot;My Blog Administration&quot;&#x27;, &#x27;&#x27;);
		$app->response()->header(&#x27;HTTP/1.1 401 Unauthorized&#x27;, &#x27;&#x27;);
		$app->response()->body(&#x27;<h1>Please enter valid administration credentials</h1>&#x27;);
		$app->response()->send();
		exit;
	}

We check if our auth credentials are okay. If they aren’t, we send a response back with the appropriate headers and warning message. As you saw earlier, we could access the Slim framework request object to get access to our POST data. We can also access the internal response object, which makes it easy for us to push in our headers and overwrite the Slim response object body with a simple HTML warning message, before finally we force the script to exit.

In Slim you can add multiple callables to a route, and they are executed in the order they are specified. What this means is that we can easily prevent access to all of our routes by adding the auth checking closure before the response closure:

	// Admin Home.
	$app->get('/admin', $authCheck, function() use ($app) {
		//...
	});

	// Admin Add.
	$app->get('/admin/add', $authCheck, function() use ($app) {
		//...
	});	
	
	// Admin Add - POST.
	$app->post('/admin/add', $authCheck, function() use ($app) {
		//...
	});

	// Admin Edit.
	$app->get('/admin/edit/(:id)', $authCheck, function($id) use ($app) {
		//...
	});

	// Admin Edit - POST.
	$app->post('/admin/edit/(:id)', $authCheck, function($id) use ($app) {
		//...
	});

	// Admin Delete.
	$app->get('/admin/delete/(:id)', $authCheck, function($id) use ($app) {
		//...
	});	

And there you have it, our admin centre is now protected. Anyone who tries to access it will see a warning message and be prompted for their credentials.

You need to give me some credentials good sir!

Step 8: Summary

Hopefully this tutorial has shown you just how quick and easy it is to get a prototype up and running with a micro framework, an ORM and template language, whilst still maintaining good separation of concerns and readable code.

A powerful templating language can prevent your views from ending up as a mix of unreadable PHP and HTML spaghetti code, and how a fluent ORM can make tedious CRUD actions quick and painless.

These are just some of the many cool things you can do with Slim, Twig and Paris. If you dig in further, you can add relationships to your models with Paris, add macro snippets in Twig to accelerate your template development and use name based routing with Slim to make linking up your website content and changing URLs trivial.

Happy prototyping and thank you so much for reading!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.pdvictor.com Peter Drinnan

    I’ve been using CakePHP for a while but this looks more flexible (not a big fan of “baking”). I have been looking for something a little more flexible for building a back-end tools to support mobile web apps and this looks like the ticket. We will see how it goes.

    Thanks Jamie.

    • Blake

      Cake is way more flexible than slim. If you added the other part (Twig and an ORM) than you would have more flexibility than with this set up. The point of this tutorial is not to be flexible but to get things done quickly. IMO, using these tools is not a permanent solution for most applications. Great article though.

  • http://www.mediaty.com Martin

    I used to use CodeIgniter php framework, for big solutions. But this looks great for ‘mini’ web application

  • http://vredniy.ru vredniy

    Great tutorial. I like this routing, it is like in Sinatra (Ruby)

  • http://ran.yefet.net Ran

    Right now your’e putting all your logic in index.php file which is not practical for big application.
    Do you have any recommendation how to implement controllers with Slim?

    • Jamie

      You can use any callable in place of a closure in my examples. So you could do:

      $app->get(‘/’, array(new Controller, ‘indexAction’));

      • Tom

        How would I need to define that Controller then? How will it be called? I assume this “controller” is a class I need to define, with the name indexAction or … ?

        class indexAction {
        function __construct() {
        ….
        }
        }

        or … ?

      • Jamie

        You’d have a controller class that looks something like this:

        <?php
        class Controller {
        public function indexAction() {
        // …
        }
        }

  • http://mediabeast.co.nz Myles

    Would you really want to rely on all these different packages?

    • Jamie

      You could say the same thing about any piece of code, library or framework.

  • Oscar B.

    Great work. The only thing is that there are a lot of escaped strings like “” , and on the twig date filter as well, those are weird symbols :D

    Excellent. Have you tried Silex? It is very very similar to Slim. The first is also developed by Fabien – the guy behind Twig and Symofony1&2.

    I’m a Symfony2 fan, but I’m thinking implementing a microframework for test and teaching purpose.

    Regards!

  • http://www.webeventures.com Prabhjeet

    Better I use CI rather than these too many packages or create my own simple framework to do all these little stuffs.

  • dude

    CakePHP uber alles!

    I do not understand, why would you have a templating engine if all you need is cache…

    • http://www.jvsoftware.com Javier Villanueva

      Easier to maintain?

  • http://www.quoidautre.fr quoidautre

    Hi,

    Very good tutorial.

    I use an excellent micro mvc framework. It have all the purpose that you need (layout, orm, mvc, bootstrap, etc) : http://www.micromvc.com/

    Fabrice

    • Panique

      microMVC is the worst thing ever, even after strugglin around with it for 8hrs i was not able to see the examples. absolutly no doc, no example, no explaination, a very confusing structure and NO community. That the main problem of systems like that: They are build by hardcore nerds, guys with big glasses and no sense to usability.

  • Jorge

    Hi there, i’m following this tutorial step by step. I’m stucked in the 5 part.
    I can’t create links for the single articles, this is the url that generates each article link ‘http://localhost/view/1′, and it doesn’t work.
    Also, i’ve tried downloading the source files, and i get the same result.

    How can i solve it?

    Thanks!

    • Jamie

      You’ll need to have mod_rewrite enabled in Apache for the clean URLs to work. If you don’t have mod_rewrite enabled you’ll need to use index.php/view/1 instead.

  • http://Simplecreativity.co.uk Dave

    Nice article.
    I’ve used idiorm and Paris on a few projects, hit the sweet spot for me in terms of functionality vs simplicity.

  • http://mediabeast.co.nz Myles

    The qoutes don’t seem to work for me?

    Also whats the purpose of these, why not just write ” ” or ‘ ‘

    • Jamie

      Hopefully someone at Net Tuts can look into fixing this.

  • skimmas

    Hi. Whille this might be useful for some, I think there might a flaw in the premisses that make you think a micro-framework is the right tool for quick prototyping.

    If you use a big framework (like Cakephp, RoR…), you probably can acomplish the same level of functionality by just creating the database table and running some of the frameworks command line scripts. That will probably be a lot faster.

    Yet I can see this being useful in prototyping some uncommon things where big frameworks CRUD automagic doesn’t fit.

  • http://www.ertankayalar.com.tr ertan

    I prefer Redbean ORM for db part. You do not need create table and define models. Easy CRUD etc.
    Twig is my choice already.
    But slim is new for me.

    Thank you for the article.

  • http://w3cafe.net Abdullah Al Mamun

    Bookmarked. Passing some good time with Laravel PHP. :)

  • Priyadarshi Lahiri

    My choice is Fat Free Framework, Idiorm & Paris for MySQL/Drizzle, Mongo PECL extension for Mongo. For advanced, start with the set as base and then build your own custom framework on top.

    • Priyadarshi Lahiri

      BTW, Fat Free comes with it’s own fantastic and simple templating engine as well.

      • http://rivernorthdesign.com Steve

        I 2nd the Fat Free Framework. It has its own SQL wrapper as well. Best part about it? It models to your habits, not the other way around.

    • http://www.willis-owen.co.uk Richard Willis-Owen

      Inspired me to write a tutorial on how to create an almost identical site but using Fat-Free Framework instead of Slim. http://www.willis-owen.co.uk/2011/09/blog-tutorial-with-fat-free-framework/
      There are a lot of similarities but I think it may be a little easier than Slim + Extras.

  • http://www.web4you.co.in Web4you

    We currently develop php application with the help of cake php framework or joomla cms and this seems to be good for small applications, I think we should give it a try :)

  • http://douseweb.com/ dewara

    I can’t work this in PHP 5.2, I have to use PHP 5.3.

    • Jamie

      Slim works with PHP 5.2, but you won’t be able to use closures. You’d have to do this instead:

      $app->get(‘/’, ‘home’);
      function home() {
      $app = Slim::getInstance();
      }

  • http://thedevelopertuts.com Bratu Sebastian

    Or you can just use CodeIgniter, the time it takes to make all this orm mappings and models and url routes is spent in codeigniter actually thinking the structure trough.

    I wouldn’t use so many libraries as CodeIgniter already has all you need for db select, caching, and I don;t believe there is a simpler micro framework.

    But that’s just me, great article !

  • Younès

    You should also check this “Flourish Unframework” + “Moor Routing” example :
    https://github.com/zares/petalon

    http://flourishlib.com/
    https://github.com/jeffturcotte/moor

  • http://www.kuxas.com compton

    A real nice combo! Thanks for a great article.

    What advantages would you say there are in using a larger framework?

    Say I create a quick demo of a concept using these packages, and then decide to go live, can I just stick with these packages or would it be better to start again using something more comprehensive?

  • charly

    Fantastic real-world example. I’m a kind of newbie at web development php (couple of years) and I’ve built some intranet stuff on vanilla PHP, but now I want something a little more structured and easy to mantain.

    Been playing around with CI which is great, but then I move on to look at slim frameworks; having been working on standard PHP I always thought that a full framework defeats the original php simplicity, and as someone said above, too much to rely on.

    Apart from that, because of work I need to use IIS/MSSQL (today with adodb and native client perfectly working). These are small applications in fact.

    I’ve liked the formula Slim + twig a lot. Now I’ll look into the other bricks you added here to see how they fare with MSSQL. But still I think I would want the models, so I should prepare something “on my own” for that.

    Question: which should be best way to handle searches parameters? I mean a search with lots of filters etc, which I now handle as search.php?name=john&order=asc&status=new ?

    I know I can use POST methods for that, but is there a good way to handle this thru GET? Thanks!

    • Jamie

      Query strings work fine in Slim, so you can continue working the same way. You could use the routing system in Slim to match search parameters in the URI, but it may get tricky the more parameters you have, and there order within the URI would be important.

  • http://vortexdev.netii.net veteran

    thnak you.
    I never heard about this framework, i will check it later :)

  • http://4bytes.com.br Rico Crivelli

    First of all, congrats!

    I’m brazilian and we use a lot of accents in Portuguese like á or ã and when I try to show it on the template the text desapear… I’ve tryed to convert to utf-8 (we use iso-8859-1) and a lot of other ways but I don’t get any result. Could you help me?

    Sorry for my English.
    =)

    • Jamie

      Twig should be setup to use UTF-8 by default. It may be worth checking out the Twig configuration options on the project website, hopefully it will point you in the right direction. http://twig.sensiolabs.org/doc/api.html

    • Offirmo

      UTF-8 must be enabled at all levels : PHP engine (multibyte runtime option), DB (collate utf8_bin + PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET NAMES utf8′), source files (declare(encoding=’UTF-8′); + being really encoded in UTF-8), output file ()
      Then it works. I’m french.

  • Mauro

    Step 5: It’s not clear ar 1st where to type $articles = Model::factory(‘Article’)->order_by_desc(‘timestamp’)->find_many();

    I had to download the code to discover it.

  • George

    I can not work because of the problem in the begging with slim: internal server error

    the .htaccess file that come with the framework is next to index but it does not work.

    i also download the source code but still not work!

  • Michael

    Hi, thanks so much for putting up up this tutorial… certainly speeded up my introduction to Slim.

    Very clear.

    Just a question or two about how to make this work in a sub directory… I have it working, but wonder if there is a better way…

    Let’s say i’m installed in abc.com/slim-demo.

    I set up my .htaccess to include
    RewriteBase /slim-demo/

    Then in my index.php i put
    define(‘SUBDIR’, ‘/slim-demo’);

    Then i can say in a few spots something like;
    array(‘action_name’ => ‘Add’, ‘action_url’ => SUBDIR.’/admin/add’)

    I then put in the template file layout.html;
    {% set foo = ‘/slim-demo’ %}

    This lets me put in my blog_home.html;
    <h1><a href=”{{ foo }}/view/{{ article.id }}”>{{ article.title }}</a> by {{ article.author }}</h1>

    This now works… I can put this in a subdirectory, but it seems a bit cumbersome… I’m sure there is a much more elegant way of doing this… what am i missing?

    Any suggestions?

    Thanks again!

    Michael

    • Jamie

      I’m not sure if there is a perfect solution to your problem, but perhaps the named routing system in Slim might help out. Slim has a function called urlFor, which you can use to work out a URL using a route name. If you name each of your routes and then expose this function to Twig you can generate URLs using route names inside your templates. I whipped up a quick gist, hopefully it points you in the right direction: https://gist.github.com/1296645

      • Michael

        Thanks so much for the very speedy reply. I’ll have a look at this in the morning and see if i can make it do my thing.

        As I read more about twig, it sure looks like the stuff i need could be passed in the render call, but so far, i’m not getting it right.

        Big thanks again for pointing out some nifty light tools!

      • arne

        can you please post more details where to put your https://gist.github.com/1296645 code? i have the same issue with rewriting the urls :/

  • http://www.jvsoftware.com Javier Villanueva

    Great tutorial, I have to admin I started playing with this combo and it’s not that “Micro” as it may look, you can still use it for at least medium sized applications I think.

    I’m a big fan of Zend Framework but I have to admit it’s an overkill for most simple/medium projects, but since the ZF is loosely coupled (I believe that is the right term) you can also use any of its components as you need them (Zend_Form, Zend_Validate, etc) with SLIM.

  • Monkeytail

    I got 2 fatal errors.. anybody familiar with this one?

    http://pastebin.com/YptU7ex9

  • Mikael

    Very good example, does anyone have any suggestions on good (and simple) login class that could extend this project? and how to implement it?

  • http://www.diggin-data.de Joachim

    Hi,

    very nice tutorial.

    Here is a logout function:

    // Logout
    $app->get(‘/logout’, function() use ($app) {
    $app->response()->header(‘WWW-Authenticate: Basic realm=”My Blog Administration”‘, ”);
    $app->response()->header(‘HTTP/1.1 401 Unauthorized’, ”);
    $articles = Model::factory(‘Article’)
    ->order_by_desc(‘timestamp’)
    ->find_many();

    return $app->render(‘blog_home.html’, array(‘articles’ => $articles)); $app->response()->body(
    ‘<h1>You have been logged out.</h1>’
    . ‘<a href=”‘.SUBDIR.’”>Home</a>’
    );
    });

    Regards,

    Joachim

  • http://tripple6.tumblr.com/ Christian Becher

    Nice Tut – thanx.

    But on Question: How to render a XML-Output – for Example for a RSS-Channel for this Blog?

    $app -> get(‘/rss/’, function() use ($app) {
    $articles = Model::factory(‘Article’) -> order_by_desc(‘timestamp’) -> find_many();
    return $app -> render(‘rss.xml’, array(‘articles’ => $articles));
    });

    and the Template:

    {% block content %}

    {% for article in articles %}

    {{ article.id }}
    {{ article.title }}
    {{ article.author }}
    {{ article.timestamp }}
    {{ article.summary }}
    http://slim.phaziz.com/article/{{ article.id }}/

    {% endfor %}

    {% endblock %}

    is always rendered as native XHML…

    Greetings Christian

  • http://www.danielweb.eti.br Daniel

    Hi Jamie,

    very nice tutorial.

    I am a Brazilian developer.
    I wonder if I can translate the tutorial and post on my blog?
    Keeping the credits of course.

    Thanks

  • ameiji

    Thanks for the introduction to Slim.

    What if I would like to integrate Twitter’s Bootstrap and use it as Twig templates? Is it possible? I couldn’t find a way how to address css and js files properly. Obviously I’m missing something here.

  • http://www.dollarstopounds.biz/ James

    Thanks for a fantastic introduction to Slim/Twig/Paris/Idiorm – I have been through this tutorial and am now trying to build my own little web app (currency conversion related). I have a question around routes:

    I have setup a route called like so: $app->get(‘/(:currency1)/(:currency2)/(:amount)’, function() use ($app) which then calls a database record and I can display the rows and the columns as needed. However, I would like to use the currency1, currency2 and amount in the template itself i.e. reference {{ data.currency2 }} – is this possible?

  • http://astaza.com/ العاب

    I like this routing, but how to register database class to $app ? can use $app->db = new dbclass();
    thanks for this topic

  • Teo

    I’m keep getting this error:

    Fatal error: Call to undefined method Slim_Http_Response::send()

    • Andrew

      The method should be write(). So, in your index.php file, in the conditional inside the Auth Check,

      $app->response()->send();

      should be

      $app->response()->write();

      Hope this helps!

  • https://github.com/superjimpupcake/Pupcake jim huang

    Check out Pupcake Microframework for PHP 5.3, It has the following major features:

    1. Slim and Silex like routing syntax or, Express Node.js like routing syntax
    2. Flexible and extensible event system and service system
    3. Support Signal/Slot swappable system event handler and also Drupal’s hook like event service handler
    4. Intuitive service handler ordering

  • https://github.com/renasboy/php-mysql-micro-framework renasboy

    Hi,

    nice, I also use a micro framework for RAD in php

    https://github.com/renasboy/php-mysql-micro-framework

    Regards,

    renasboy

  • Wayne

    You never, never ever want to call the delete route with a GET method.. ALWAYS use method POST or DELETE when deleting

  • Dias

    I`m having a problem when I add any text like “á ç aaaa” on the text boxes, it inserts in the db but dont show it.

    • Diaz

      Just fixed :x

  • http://warcraftgold1.blog.fc2.com/ Eloise Tremblay‘s articles

    I would like to express appreciation to the writer for bailing me out of this particular setting. Because of scouting throughout the internet and finding tricks that were not helpful, I figured my life was well over. Existing without the strategies to the problems you’ve sorted out through the short article is a serious case, and ones that would have in a wrong way affected my career if I hadn’t noticed your website. Your own talents and kindness in touching all areas was invaluable. I’m not sure what I would’ve done if I hadn’t discovered such a subject like this. I’m able to at this point relish my future. Thanks a lot so much for this reliable and sensible guide. I will not think twice to endorse the website to any person who should have support on this issue.

  • John BF

    Hi there. Speaking about rapid PHP prototyping you can look at PHappy – young but as i see very fast-developing project. Simple typical components, layout and javascript are included, pretty brief syntax. Good luck!

    https://github.com/ptrofimov/phappy

  • http://laravelsnippets.tk/ Ken

    Nice tuts! Its very helpful. I learned a lot! :) Thanks

  • http://www.facebook.com/csrui Rui Cruz

    With a few updates the tutorial still helps a lot.

    I’m having trouble accessing the “flash” message variable. Anyone can shed a light?

  • http://www.famesbond.com/ aditya menon

    Good read, thanks. CodeIgniter is not a ‘micro framework’ technically, but I still like to use it for rapid prototyping. Doing this sort of a thing can help me teach mixing and matching ‘small tools that do one thing and do it well’ to achieve stuff, instead of a giant monolith :) I still love CodeIgniter though…

  • Offirmo

    Thank you very much ! With this article, I was able to set up a custom mini-site for a charity event in a few days. All thanks to you !
    Just a change : for even faster prototyping, I switched the ORM to RedBean.
    Best regards.

  • Largo

    Heads up if you’re left with an error 500 or just a white screen. Try to use double quotes in the require statements instead of single quotes. I don’t know why but this was the solution.

    Also make sure the mod rewrite extension is activated in apache.

  • Edison Leon

    Awesome work, thank you so much

  • Pasika

    Hi, can you provide zip with working version, because i cant run it succsessfull.
    thx