Getting Started with the Fuel PHP Framework

Getting Started with the Fuel PHP Framework

Tutorial Details
  • Program: Fuel PHP Framework
  • Version: 1.0.1
  • Difficulty: Easy
  • Estimated Completion Time: 1 hour

This two-part tutorial will get you up and running with the Fuel PHP framework. We’ll start with the basics, and then move onto some more advanced topics in part two! Let’s get started.


Introduction

Fuel is a new PHP Framework built specifically for PHP 5.3, which uses the tried and tested MVC architecture for logical code separation and combines the best ideas of some existing frameworks with improvements and ideas of its own. A final v1.0 has only recently been released, but, already, the framework has a large following after nine months of heavy development. This article will get you up to speed on how to make sites with Fuel – but first, let’s talk a bit about the architecture.

Understanding MVC

The MVC (Model-View-Controller) architecture is used by many existing frameworks such as CodeIgniter, Zend Framework, Symphony and Ruby on Rails. If you’re familiar with any of these frameworks, you have a head start!

For those who are new to this architecture, MVC is an approach to separating your code depending on what role it plays in your application. In the application flow, it starts with a Controller that is loaded by Fuel. A method is then executed which works out what data to retrieve using a Model. Once that is done, the Controller can decide what View(s) to load (if any). Views contain the output your visitors get to see, AJAX responses or error messages.

A more in depth explanation of MVC from Fuel’s perspective can be found in the Fuel MVC Documentation; so we’ll skip to the good stuff.

We’ll start off with some of the very basics to get brand new users going. If some of this seems obvious then please skip down a bit to get to some of the more exciting features.


Step 1: Installation

Installation is as simple as grabbing a copy from GitHub or downloading a ZIP from the site. You can also use a one-liner installation if you are using a *nix system, such as Linux, Mac OS X, etc which requires Git to run. Installing Git is quite easy, and makes things a lot easier as you develop your applications:

$ curl get.fuelphp.com/oil | sh 

This will install a very limited version of “oil”, which is the name of the command line utility you can use when working with Fuel applications. This stripped down version can be used to create applications:

$ oil create blog

This will create a blog folder in your current directory which will contain the base framework. If you come across any problems then take a look at the more detailed installation instructions.

Assuming you ran this command in your local servers web root, we should be able to browse to http://localhost/test/public and see the Welcome page.

File Structure

The root of your application should contain three main items:

  • fuel/ – Where all of your PHP code is going to live.
  • public/ – Anything you want to be directly accessible in the browser, so JS, CSS, images, etc.
  • oil – An executable, which is a more feature-full version of the oil installed earlier that can run command line tasks such as generating code or interactive debugging within your application. It’s optional, so you can delete it if you don’t like the command line.

Within fuel/ we have some important folders:

  • app/ – All application specific PHP code goes in here, including your Models, Views and Controllers.
  • core/ – This is where Fuel itself lives. If you use Git, this will be a sub-module that can be updated easily.
  • packages/ – Fuel separates out certain logic into packages to avoid bloating the core. By default, Fuel will contain three packages: oil, auth and orm. These packages will not be loaded unless you require them, so we’ll filter through them later on.

The important part here is the app/ folder:

  • config/ – Configuration files for various classes and the general “config.php” file lives here.
  • classes/ – This is where all Controllers, Models, helper classes, business logic libraries, etc will go. If need to write a class to use in your code, it will probably go in here. Names are all lowercase.
  • classes/controller/ – This is where Controllers are placed.
  • classes/model/ – Location for your models, although they are really only just another class.
  • views/ – Put your view files in here in folders or just in the root. There are no specific naming conventions for views.

Before going through any more theory, let’s write some code.


Step 2: Hello World

Let’s delete the fuel/app/classes/controller/welcome.php controller and make our own, called hello.php.

In that file, add the following code:

class Controller_Hello extends Controller {

    public function action_index()
    {
        echo "Hello World!";
    }
}

Now if we browse to http://localhost/test/public/index.php/hello, you should see “Hello World!” output to the browser. The action_ prefix tells us this is a routeable method and not some callback or other shared method, and means you can use method names, like “list,” without PHP getting confused.

If we want this hello controller to be our “root” controller instead of the now gone welcome.php, we only need to open fuel/app/config/routes.php and change the _root_ route like so:

return array(
	'_root_'  => 'hello',  // The default route
);

Your First View

Make a file fuel/app/views/hello.php and add:

<h1>Hello!</h1>
<p>Hey <?php echo $name ?>, how's it going?</p>

Next, modify your controller a bit:

class Controller_Hello extends Controller {

    public function action_index()
    {
        echo "Hello World!";
    }

    public function action_buddy($name = 'buddy')
    {
        $this->response->body = View::factory('hello', array(
            'name' => $name,
        );
    }
}

Now, if you load http://localhost/test/public/index.php/hello/buddy or http://localhost/test/public/index.php/hello/buddy/John , you will see the $name variable being passed through from the method to the view. Essentially extract() is being run on the view.


Step 3: Basic Configuration

As you can see, Fuel can do basic Controller/View stuff out of the box, but if we want to do much more, we’ll need to make some basic configuration changes. Let’s start by opening up fuel/app/config/config.php and setting a few things up:

/**
 * index_file - The name of the main bootstrap file.
 *
 * Set this to false or remove if you using mod_rewrite.
 */
'index_file'	=> 'index.php',

If you have mod_rewrite installed, we can change this value to be an empty string, which will let us remove index.php from our URL’s. There is a .htaccess file in public/ which will support this.

Next we need to set up the database configuration, which, for the sake of this tutorial, we’ll assume is MySQL. Create your database with your desktop GUI, phpMyAdmin, or etc command line:

 mysql> create database blog_example; 

Open up fuel/app/config/db.php and set the Fuel::DEVELOPMENT array, like so:

Fuel::DEVELOPMENT => array(
	'type'			=> 'mysql',
	'connection'	=> array(
		'hostname'   => 'localhost',
		'database'   => 'blog_example',
		'username'   => 'yourmyseluser',
		'password'   => 'yourmysqlpassword',
		'persistent' => false,
	),
	'table_prefix' => '',
	'charset'      => 'utf8',
	'caching'      => false,
	'profiling'    => false,
),

Next, lets enable the orm and auth package by un-commenting the following lines:

/**
 * These packages are loaded on Fuel's startup.  You can specify them in
 * the following manner:
 *
 * array('auth'); // This will assume the packages are in <code>PKGPATH</code>
 *
 * // Use this format to specify the path to the package explicitly
 * array(
 *     array('auth'	=> PKGPATH.'auth/')
 * );
 */
'packages'	=> array(
	'orm',
	'auth',
),

This step is only required if you wish to use them – which in this tutorial we will be.

Optional: Using a Virtual Host

The last step of setup is to create a virtual host. You do not need to do this, but it means you can use a real URL and remove /public/ from your URL’s. If you are using Apache, then a simple chunk like this should do the trick:

<VirtualHost 127.0.0.1>
	DocumentRoot /home/phil/Sites/blog/public
	ServerName local.blog

	<Directory /home/phil/Sites/blog>
		Options All
		AllowOverride All
	</Directory>
</VirtualHost>

If this was a live site, we’d be adding the ServerName as “myawesomeblog.com” instead of “local.blog” but this works for our demo. Once you’ve added “127.0.0.1 local.blog” to your /etc/hosts file you should be ready to go. If you want to skip this step then adjust URL’s in this article.


Step 4: Kick-starting Development

With this basic understanding of how Controllers, Views and Configuration works, you could probably hop into the documentation and get started rather quickly, but to really get going, the best way has to be Scaffolding.

Scaffolding is not a new concept and is best known for its place in the framework Ruby on Rails. It is essentially a very simple way to create code based on a few assumptions through the command line. You want to add, edit and delete an entity which you name and provide fields for. It is done through oil and the sub-command “oil generate scaffold

So if we want to build a basic blog, we only need to write “$ oil g scaffold post title:string summary:varchar[250] body:text“. Oil will be very verbose about what it is doing and tell you all the files created:

	Creating model: /home/phil/Sites/blog/fuel/app/classes/model/post.php
	Creating migration: /home/phil/Sites/blog/fuel/app/migrations/001_create_posts.php
	Creating controller: /home/phil/Sites/blog/fuel/app/classes/controller/posts.php
	Creating view: /home/phil/Sites/blogfuel/app/views/posts/index.php
	Creating view: /home/phil/Sites/blog/fuel/app/views/posts/view.php
	Creating view: /home/phil/Sites/blog/fuel/app/views/posts/create.php
	Creating view: /home/phil/Sites/blog/fuel/app/views/posts/edit.php
	Creating view: /home/phil/Sites/blog/fuel/app/views/posts/_form.php
	Creating view: /home/phil/Sites/blog/fuel/app/views/template.php 

Note: Models generated by scaffolding use the ORM package so make sure it is enabled as described above.

You’ll see here a model named “post“, a migration (more on those later) a controller “posts” and a bunch of views. The fields are all generated based on the arguments provided, which are fieldname:fieldtype[optional-length]. For title, we used “:string” which, as long as you are using MySQL, will alias :varchar[255], but any DB type is supported.

With this command run we need to run our migrations. A migration is a series of changes that need to be made to a database. This becomes useful when multiple developers are working on a project, as each developer can add a migration and you can run a single command to make sure your local copy is up to date. No more “missing field’ or “table does not exist” errors after pulling the latest development copy!

To run this migration, simply type:

$ oil refine migrate
Migrated to latest version: 1.

Now you can view what Oil has made for you by going to http://local.blog/posts

If you want to create controllers, models and migrations separately and not all together like this, you can do so easily with oil g controller, oil g migrate, oil g model, etc.

Templating

You may have noticed, in the step above, that Oil created a file:

	Creating view: /home/phil/Sites/blog/fuel/app/views/template.php 

This will be created when you first run a scaffolding command as all views are wrapped with a “template” or “layout” – which is a header and footer wrapping your content. To change from the default design, all you need to do is edit this template, include your own CSS, add a logo and enter whatever metadata you like.

When you create new controllers manually, you can extend ‘Controller_Template‘ instead of the usual ‘Controller‘ to have this template wrapped around any Views loaded in the controller.

If you wish to use a different template for a controller, you simply change the $template property to something different.

class Users extends Controller_Template {
    public $template = 'alternative';
}

This will use the fuel/app/views/alternative.php view file instead of the usual fuel/app/views/template.php.

Working with Forms

One of the most important aspects of any application is form submission. This is how data is captured from a user; it could be a login, a comment, a shopping cart checkout, etc. This is all done with HTML normally, but Fuel gives you some helpful methods to make this process a lot easier. They are optional, so if you are an HTML fanatic, then carry on, but to speed things up, read on:

<?php echo Form::open(); ?>
	<p>
		<?php echo Form::label('Title', 'title'); ?>
<?php echo Form::input('title', Input::post('title', isset($post) ? $post->title : '')); ?>
	</p>
	<p>
		<?php echo Form::label('Summary', 'summary'); ?>
<?php echo Form::input('summary', Input::post('summary', isset($post) ? $post->summary : '')); ?>
	</p>
	<p>
		<?php echo Form::label('Body', 'body'); ?>
<?php echo Form::textarea('body', Input::post('body', isset($post) ? $post->body : ''), array('cols' => 60, 'rows' => 8)); ?>
	</p>

	<div class="actions">
		<?php echo Form::submit(); ?>
	</div>

<?php echo Form::close(); ?>

This is a very simple form that will work with both create and edit. For each input, if it can find a match in POST it will use it; otherwise, it will look for the $post variable and input the value (good for editing).

The real benefit of these helpers does not come from cleaner syntax as you might think, but in that it allows the framework to programmatically wrap your form. This means Fuel can automatically embed attributes to all forms to make sure data is sending in the right character set and enable CRSF (Cross-Site Request Forgery) automatically.

Validating your Forms

Validation is a simple way to ensure that certain information has been supplied in a form submission in the correct manner. It can match certain patterns, data types or conditions and will help improve the integrity or the data.

By default, validation is not used by Scaffolding, because it’s complicated to make assumptions about what the developer expects to be held in the data. For this reason the validation is optional but is quite easy to add into your generated controllers or work with from scratch.

Lets take a look at how a “Create Post” method may look for our blog:

	public function action_create($id = null)
{
	if (Input::method() == 'POST')
	{
		$val = Validation::factory();

		// Add a field for title, give it the label "Title" and make it required
		$val->add('title', 'Title')
			->add_rule('required');

		// Now add another field for summary, and require it to contain at least 10 and at most 250 characters
		$val->add('summary', 'Summary')
			->add_rule('required')
			->add_rule('min_length', 10)
			->add_rule('max_length', 250);

		$val->add('body', 'Article body')
			->add_rule('required');

		if ($val->run())
		{
			// Make a post based on the input (array)
			$post = Model_Post::factory($val->validated());

			// Try and save it
			if ($post->save())
			{
				Session::set_flash('notice', 'Added post #' . $post->id . '.');
			}
			else
			{
				Session::set_flash('notice', 'Could not save post.');
			}
			
			Response::redirect('posts');
		}
		else
		{
			$this->template->set('error', $val->errors());
		}
	}

	$this->template->title = "Posts";
	$this->template->content = View::factory('posts/create');

}

We can see here that we are telling the Validation class – which is autoloaded like all classes) which fields we care about. We are then assigning rules and giving them labels for humans to read. If $val->run() is true, we make a new Model_Post instance using the factory, and send $val->validated() which contains an array of all the submitted data. With that, we can simply save the instance, which uses ORM to do everything for you.

If any of the validation rules return false, then $val->run() will fail and we are given an array of errors in $val->errors() which we can send back to the user. The default template.php looks for a “notice” piece of flashdata (part of the session class) or just normal view data and can output a string or an array, so this works perfectly.

Using your knowledge of validation and form building, you can start to make any Controller based applications you like.

Working with Tasks

Tasks are similar to controllers, but cannot be accessed via a URL or routed to in any way. Instead, they are run via the “oil refine” sub-command in the terminal. This is great for creating interactive shell scripts that have access to your codebase and makes creating secure cron jobs a breeze.

Some frameworks suggest you use wget, curl or something similar to run a controller to make a cron job, but this can lead to potential security or consistency concerns with cron jobs being run out of time to cause malicious or unexpected results. This way, it is protected from the outside world completely.

For an example of a task, take a look at the provided “robots” task in fuel/app/tasks/robots.php:

class Robots {

	public static function run($speech = null)
	{
		if ( ! isset($speech))
		{
			$speech = 'KILL ALL HUMANS!';
		}

		$eye = \Cli::color("*", 'red');

		return \Cli::color("
					\"{$speech}\"
			          _____     /
			         /_____\\", 'blue')."\n"
.\Cli::color("			    ____[\\", 'blue').$eye.\Cli::color('---', 'blue').$eye.\Cli::color('/]____', 'blue')."\n"
.\Cli::color("			   /\\ #\\ \\_____/ /# /\\
			  /  \\# \\_.---._/ #/  \\
			 /   /|\\  |   |  /|\\   \\
			/___/ | | |   | | | \\___\\
			|  |  | | |---| | |  |  |
			|__|  \\_| |_#_| |_/  |__|
			//\\\\  <\\ _//^\\\\_ />  //\\\\
			\\||/  |\\//// \\\\\\\\/|  \\||/
			      |   |   |   |
			      |---|   |---|
			      |---|   |---|
			      |   |   |   |
			      |___|   |___|
			      /   \\   /   \\
			     |_____| |_____|
			     |HHHHH| |HHHHH|", 'blue');
	}
}

To run this jestful task just type “oil r robots” or “oil r robots 'Kill all Mice' ” to make the robot say something else.


Summary

If you followed each step, you’ll have installed Fuel, learned where the important files go, configured a basic install to run on Apache with mod_rewrite (other servers work fine too), and created simple controllers and views using forms and validation. With scaffolding available to generate code to pick apart, there should be plenty of code to learn from!

At this point, you should have enough knowledge to play around and create some really simple apps – that is, until Part two of this series, where we will go through the process of creating and extending Base Controllers to create your frontend/backend separation. We’ll also review advanced ORM, authentication drivers, and file uploads. Stay tuned!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://spareshade.com clone tempus

    The CI is great. But I just can’t wait for Fuel to fill its Documentation gaps.
    So far it looks really flexible.
    Thank you for putting in your effort and time.

  • Ian

    First thank you to you Phil and the other developers.

    Second, thank you Phil for the tut.

    I think it’s a good thing to have more than one option so I’m glad to hear your positive comments on CI. I am currently working with CI thanks to the vast amount of tutorials that helped me get started. I learn better from examples than I do from documentation because sometimes it just takes seeing something in action for it to make sense. I loved the CI from scratch series here at nettuts and would love to see a similar series on fuel. Videos are awesome and not for lazy people as someone said, but making screen casts takes time and work so I’m not complaining. The written tutorial is great.

    I understand you and everyone else involved in the development have a lot going on so making a tutorial series is a lot of extra work and I appreciate you taking the time to share what you will. You could just tell people RTFM and leave slower folks like me out in the cold but you choose to share your knowledge and that’s real cool :-).

    Also, while I don’t like negativity, I like reading through the comments when they get argumentative because it’s an opportunity for me to learn. I’ve seen your name around the php community enough to know that you have expert knowledge so I like to read your responses.

    Thank you

  • Ian

    couple of minor issues from the start. I get 404 error if I don’t capitalize the h in “hello” in the url. I double checked that my file name is all lower case hello.php and the class is “Controller_Hello” and tried it with “Controller_hello” but nothing changed.

    dev.local/fuel-blog/public/index.php/Hello works

    dev.local/fuel-blog/public/index.php/hell gives 404 error.

    Putting it in the config/routes.php as all lowercase makes it work for the main controller but it is going to be a problem when I want to load another controller.

    I’m using Ubuntu 10.04 if that has anything to do with the problem. In all the CI, Kohana, and in previous fuelphp tuts I’ve done this is the first time I’ve had this problem so I don’t think it’s a server issue.

    Anyway, it’s minor but I need to get it figured out.

    • Ian

      Thought I’d post the answer to my minor issue in case anyone else has it.

      The good folks over at the fuelphp forum found it for me.

      The problem was this third line in config/routes.php

      ‘hello(/:name)?’ => array(‘welcome/hello’, ‘name’ => ‘hello’),

      It has to do with the “hello” method that comes by default as a method in the welcome controller and it still causes the 404 I was getting even after deleting the welcome controller. It’s part of advanced routing in the documentation. Deleting this line will resolve the issue.

      • Esteve

        Great!! I faced the same problem.

  • Rizalmovic

    Great framework..

  • rahul

    done till step 3 and cant see any hello page except PHPinfo() page !!! any suggestion please :)

  • Clay Branch

    I found a minor bug in the code for the first view

    public function action_buddy($name = ‘buddy’)
    {
    $this->response->body = View::factory(‘hello’, array(
    ‘name’ => $name,
    );
    }

    You’re missing the second closing parenthesis after ‘name’ => $name,

    • Esteve

      Why the code is not fixed by the author?

  • dan

    i know it´s always easy to criticize, but.. if you want to write tutorials with “Difficulty: Easy”, please start at the beginning and stop skipping steps which are important to get things to work. it not easy for newbies to follow your instructions if you don´t write exactly where the code should be changed. i think this makes the difference between tutorials and well designed tutorials. i imagine many guys skipped fuelphp because of such tutorials like this one.

  • http://www.j7mbo.co.uk J7mbo

    I’m trying to follow this tutorial as this is the only one I can find on the internet, but there’s a massive issue here…

    Step 2! After creating my hello.php and navigating to http://fueldev/test/public/index.php/hello I get the following error:

    ————–

    Fuel\Core\FuelException [ Error ]: The controller action called or it’s after() method must return a Response object.

    COREPATH/classes/request.php @ line 426

    421
    422
    423 // Get the controller’s output
    424 if (is_null($response))
    425 {
    426 throw new \FuelException(‘The controller action called or it\’s after() method must return a Response object.’);
    427 }
    428 elseif ($response instanceof \Response)
    429 {
    430 $this->response = $response;
    431 }
    Backtrace
    ———————————

    • BobS

      I had the same problem and changed the line

      echo “Hello World!”;

      to

      return new Response(“Hello World!”);

  • BobS

    This also works:

    echo “Hello World!”;

    as the base controller will crete the response object.

    • BobS

      Sorry should be:

      return “Hello World!”

  • romero

    i just discovered fuel
    way back i create small projects in CI, but its been long time and i have to relearn things again

    i got very interested in fuel
    i just hope that its dev are not like kahona devs in that they keep the ins and out of kohana to themselves and not even God can get them to create a basic hello world using the CURRENT version. So I hope fuel’s devs are more embracing and keep basic tutorials current to attract new users and supporter of what it looks to me to be a great framework. If they are community-center and not self-centered then I want in in the fuel citizenship.

    anyways (hi to all, by the way) this tutorial seem outdated – i tried it and cant get it to work

    - i had to add <?php in the controller, else i get page not found
    - in the initial part of the tut it will work only if i use single quotes
    - so i put in response->body = View::factory(‘hello’, array(‘name’ => $name));

    }
    }

    please advise – -what did i do wrong?
    thanks

    • Namal

      I also faced same problem… As the manual it should as this.

      public function action_buddy($name = ‘buddy’) {
      return $this->response->body = View::forge(‘hello’, array(
      ‘name’ => $name,
      ));
      }

  • http://jromero.me Javier Romero

    NOTE TO EVERYONE: This tutorial is “broken”, it will mislead you and in particular the code is incomplete or just plain wrong. I recommend to use it as a reference, if that, and go to the documentation for how to really work in Fuel. This tutorial doesn’t do much justice. The documentation should get you there pretty easily.

    Documentation:
    http://docs.fuelphp.com/

  • http://www.simonkincaid.com Simon Kincaid

    What a waste of time this was. Was really looking forward to learning from a good tutorial but the code in this tut is broken, as the previous comment said. I’m amazed that this code hasn’t been fixed, but will persevere with FuelPHP to see if it’s the next step up for me from CI. The major thing I have noticed with FuelPHP is the language used in the documentation isn’t as straightforward as it could be.

  • mike

    Really Great! It just works for me. Thank you.

  • RomanTsjupa

    For those interested in FuelPHP, I found this awesome callgrind function call map of Fuels inner operations, so you can see how it works: http://phpixie.com/blog/php-framework-comparison/