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!
Comments