Build an Admin Panel with the Fuel PHP Framework

Build an Admin Panel with the Fuel PHP Framework

Tutorial Details
  • Program: Fuel PHP Framework
  • Version: 1.1.0
  • Difficulty: Easy
  • Estimated Completion Time: 2 hours

In the first part of this series, we took a look at the basics of the FuelPHP framework. In this second-part, we’ll be stepping it up a gear and move onto some more advanced topics! We’ll be creating an admin panel for our application, cover the common uses of the ORM and use the Authentication package to restrict access.

Join me after the break to get started!


Introduction

Since the first article Fuel has been renamed to FuelPHP. Also unlike the first article which was based on v1.0.1 this article requires v1.1.0 so a few little things are different. All the theory you have learnt from the first article is still accurate and not much has changed so this should be easy.


Step 1 - Set Up Oil

If you have not already installed the command-line utility oil and are lucky enough to be running on Linux, Mac, Solaris, etc then do so with the following command:

$ curl get.fuelphp.com/oil | sh

Step 2 - Create a New App

The oil command will help you create new projects with a few key-strokes and alias php oil when inside your FuelPHP applications:

$ oil create Sites/blog
$ cd Sites/blog

This will set up a blog application for us and assuming you have Apache or some other web server running on your “Sites” folder you should be able to load the following URL and see the welcome page.

alt text

Now that FuelPHP is alive and your web server is clearly working, we can start configuring our app.


Step 3 - Configuring Your App

Open up your favourite editor and we’ll start by setting up a database connection and configure the application. This is almost identical to v1.0.x, so create a database and set up your SQL users however you normally do. When it comes to database config there are two differences:

  • PDO is now the default driver
  • FuelPHP v1.1 has environment-based config folders now.

These changes are pretty simple, but you can swap back to using the native MySQL driver if you like. PDO is more useful for developers as it means that your application will work with just about any database engine not just the few that had specific FuelPHP drivers built for them. That means this could just as easily be SQLite or PostgreSQL.

Just open up fuel/app/config/development/db.php and modify your config, where dbname=blog is whatever your database is called and your own username and password for the database server:

return array(
  'default' => array(
 	 'connection'  => array(
 		 'dsn'  	=> 'mysql:host=localhost;dbname=blog',
 		 'username' => 'root',
 		 'password' => 'password',
 	 ),
  ),
);

Next you will just need to open fuel/app/config/config.php and enable the auth and orm packages as suggested in the first post.

/**************************************************************************/
/* Always Load                    */
/**************************************************************************/
'always_load'  => array(

	'packages'  => array(
		'auth',
'orm',
	),

In this config file, we need to make one small change to the whitelisted_classes array which will allow us to pass validation objects to the view:

	'whitelisted_classes' => array(
		'Fuel\\Core\\Response',
		'Fuel\\Core\\View',
		'Fuel\\Core\\ViewModel',
		'Fuel\Core\Validation',
		'Closure',
	),

Setting up Groups

The auth package included with FuelPHP is driver based and by default we are using “SimpleAuth” which is the only driver included in the package. When you are more experienced with FuelPHP, you can start to create custom drivers to integrate with other users’ systems – such as third-party forums, content management systems, etc.

To enable groups for SimpleAuth, we simply open up fuel/packages/auth/config/simpleauth.php and set groups to the following:

return array(
  'groups' => array(
 	  -1 => array('name' => 'Banned', 'roles' => array('banned')),
 	  0	=> array('name' => 'Guests', 'roles' => array()),
 	  1	=> array('name' => 'Users', 'roles' => array('user')),
 	  50 => array('name' => 'Moderators', 'roles' => array('user', 'moderator')),
 	  100  => array('name' => 'Administrators', 'roles' => array('user', 'moderator', 'admin')),
  ),
);

These could, of course, be anything, but are pretty standard for most apps and will work for this tutorial.


Step 4 - Creating Users

As we are building an admin panel, we need to create the users table and then populate it with a user record who will be the first administrator. We could use something like phpMyAdmin or a GUI like Navicat, but it’s better to do things via Oil so we stay within our codebase. This means password hashing is salted correctly with whatever driver is being used – and is how we’ll be doing it:

$ oil generate model users username:varchar[50] password:string group:int email:string last_login:int login_hash:string profile_fields:text
  Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/user.php
  Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/001_create_users.php
$ oil refine migrate

This creates a user model for us and creates another migration that will build our user table when the oil refine migrate task is run. Next we have to create an Administrator user, which, again, we could do via a GUI but where’s the fun in that?

$ oil console
Fuel 1.1-rc1 - PHP 5.3.6 (cli) (Sep  8 2011 19:31:33) [Darwin]
>>> Auth::create_user('admin', 'password', 'phil@example.com', 100);
1
-- Ctrl + C to exit

We’ve used the Oil Console to write code in real-time and get a response. Auth::create_user() was passed a username, password, email address and the group_id for admins, which for now we’ll just use 100 – which we set in the config. The 1 is a response from the code, which means user_id has a value of 1.


Step 5 - Code Generation

Generators are a great way to build a bunch of code from scratch and getting a running start.

As explained in the first article we can use scaffolding to build large chunks of an application quickly. This is done through the oil command and is all very optional, but it is a great way to build a bunch of code from scratch. Some people look at code generation as “tools for people who don’t know how to code” or think its some kind of black magic, but if you are new to a framework and do not want to have to learn how to put everything together then having a system make code for you is not such a bad thing.

FuelPHP v1.1 takes the code generation one small step further. Instead of just creating scaffolding (unprotected CRUD) you can now generate Admin code. This works in exactly the same way but implements a simple admin template, admin controller, etc and uses the auth package to lock down your generated code. Taking advantage of the Twitter Bootstrap, this all looks good enough to use and with only a bit of tweaking you’ll have an app that you can ship.

This is done via the command line using the oil command. We’ll generate some code then walk through it.

$ oil generate admin posts title:string slug:string summary:text body:text user_id:int
	Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/base.php
	Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin.php
	Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/template.php
	Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/dashboard.php
	Creating views: /Users/phil/Sites/blog/fuel/app/views/admin/login.php
	Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/002_create_posts.php
	Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/post.php
	Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin/posts.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/index.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/view.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/create.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/edit.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/posts/_form.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/template.php

This is quite a bit of code because it is the first time it has been run. FuelPHP will set up a few basic templates and files, then build the MVC components for the posts section. Remember, this is just like writing the code yourself, but quicker. You can take a look at this output by going to /blog/public/admin/posts:

Posts - Admin Generated code

Understanding Controllers

We’ve added a Controller_Base which will contain logic for your entire app, so every controller can extend from this. The file simply contains:

abstract class Controller_Base extends Controller_Template {

	public function before()
	{
		parent::before();

		// Assign current_user to the instance so controllers can use it
		$this->current_user = Auth::check() ? Model_User::find(Arr::get(Auth::get_user_id(), 1)) : null;

		// Set a global variable so views can use it
		View::set_global('current_user', $this->current_user);
	}

}

By extending Controller_Template, all views will be wrapped by a template automatically. Then in the before() function we do a little bit of logic to get the current user and make it available as $this->current_user in controllers and $current_user in views.

Another controller will be built called Controller_Admin which extends Controller_Base, so as well as having the current user being built we can check to see if a user is actually an admin:

abstract class Controller_Admin extends Controller_Base {

	public $template = 'admin/template';

	public function before()
	{
		parent::before();

		if ( ! Auth::member(100) and Request::active()->action != 'login')
		{
			Response::redirect('admin/login');
		}
	}

	// ....

}

You’ll notice that this controller sets a custom template so instead of looking for fuel/app/views/template.php, it will look for fuel/app/views/admin/template.php. Then if a user does not match member(100) – the admin group ID set earlier – they will be sent off the the login page.

Extending Controllers

One very handy feature that FuelPHP has is to allow you to extend other controllers. Normally they are just loaded directly by the Request class after being routed to by the URL, but sometimes it is useful to extend controllers to share logic or methods. In this case, we are already checking permissions in Controller_Admin so we can extend that controller to reuse this logic.

Controller_Admin_Posts extends Controller_Admin. This means it contains the same before() check and therefore is protected in the same way as any other controller in your admin panel.

Now What?

Code generation is basically just the first step in working on an application. We still need to tweak our forms and create a frontend. For example, if you go to create or edit a post it will show the user_id field as a text box.


Step 6 - Updating the CRUD Forms

We’re going to want to modify our action_create() method in fuel/app/classes/admin/posts.php so we have a list of users available. To do this we can replace the method with this code:

public function action_create($id = null)
{
	$view = View::forge('admin/posts/create');

	if (Input::method() == 'POST')
	{
		$post = Model_Post::forge(array(
			'title' => Input::post('title'),
			'slug' => Inflector::friendly_title(Input::post('title'), '-', true),
			'summary' => Input::post('summary'),
			'body' => Input::post('body'),
			'user_id' => Input::post('user_id'),
		));

		if ($post and $post->save())
		{
			Session::set_flash('success', 'Added post #'.$post->id.'.');
			Response::redirect('admin/posts');
		}

		else
		{
			Session::set_flash('error', 'Could not save post.');
		}
	}

	// Set some data
	$view->set_global('users', Arr::assoc_to_keyval(Model_User::find('all'), 'id', 'username'));

	$this->template->title = "Create Post";
	$this->template->content = $view;
}

This is the same as the code before with two changes:

$view = View::forge('admin/posts/create');

This creates a new View object. We can assign properties to this view by setting them as properties, so our users data can be passed easily and would normally work a little like this:

$view->users = array(1 => "User 1", 2 => "User 2");

Now we make a similar update to action_edit():

public function action_edit($id = null)
{
	$view = View::forge('admin/posts/edit');

	$post = Model_Post::find($id);

	if (Input::method() == 'POST')
	{
		$post->title = Input::post('title');
		$post->slug = Inflector::friendly_title(Input::post('title'), '-', true);
		$post->summary = Input::post('summary');
		$post->body = Input::post('body');
		$post->user_id = Input::post('user_id');

		if ($post->save())
		{
			Session::set_flash('success', 'Updated post #' . $id);
			Response::redirect('admin/posts');
		}

		else
		{
			Session::set_flash('error', 'Could not update post #' . $id);
		}
	}

	else
	{
		$this->template->set_global('post', $post, false);
	}

	// Set some data
	$view->set_global('users', Arr::assoc_to_keyval(Model_User::find('all'), 'id', 'username'));

	$this->template->title = "Edit Post";
	$this->template->content = $view;
}

However, because the create.php and edit.php views share a theme partial _form.php, and properties only set variables to that one specific view we need to use the View::set_global() method:

$view->set\_global('users', Arr::assoc_to_keyval(Model\_User::find('all'), 'id', 'username'));

This uses the Model_User object to get all of our users, then flattens them to an associative array for our form.

The HTML now needs to change, so delete the div wrapping “slug” – we’ll do that ourselves and change the user_id field from being a input box to a select box:

<div class="clearfix">
	<?php echo Form::label('User', 'user_id'); ?>

	<div class="input">
		<?php echo Form::select('user_id', Input::post('user_id', isset($post) ? $post->user_id : $current_user->id), $users, array('class' => 'span6')); ?>

	</div>
</div>
User dropdown form

This will set the box to show all users and default to the current logged in user if none are provided. That is the only tweak we need to make at this point, so let’s make a frontend!

The Frontend

Creating a basic blog frontend is really simple so won’t worry about using code generation.

Create a new controller fuel/app/classes/controller/blog.php:

class Controller_Blog extends Controller_Base
{
	public function action_index()
	{
		$view = View::forge('blog/index');

		$view->posts = Model_Post::find('all');

		$this->template->title = 'My Blog about Stuff';
		$this->template->content = $view;
	}
}

And the fuel/app/views/blog/index.php view file:

<h2>Recent Posts</h2>

<?php foreach ($posts as $post): ?>

	<h3><?php echo Html::anchor('blog/view/'.$post->slug, $post->title) ?></h3>

	<p><?php echo $post->summary ?></p>

<?php endforeach; ?>

This is just a simple loop through the $posts array which contains all your articles.

Comment form

A foreach loop, a hyperlink and a summary is all we need on this view file and we’ll make another view file to actually see the post. We’ll call this controller method action_view() and make a view file called view.php:

<h2><?php echo $post->title ?></h2>

<p><strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>)</p>

<p><?php echo nl2br($post->body) ?></p>

This is the method for the blog controller:

public function action_view($slug)
{
	$post = Model_Post::find_by_slug($slug);

	$this->template->title = $post->title;
	$this->template->content = View::forge('blog/view', array(
		'post' => $post,
	));
}

The find_by_slug() method is a “magic method” that will build WHERE slug = "foo" in your query and return a single Model_Post instance with that data.

Comment form

Now people can look at your – horribly unstyled – website and see a basic blog, and you have an admin interface to manage it!


Step 7 - Using the ORM

So far we’ve been using the ORM for our models to do basic CRUD but we’ve not yet seen anything to do with relationships. The ORM makes this incredibly easy as, well it stands for “Object Relational Mapping” for a reason. To set up relationships all we need to do is modify our models a little bit to explain how the ORM should relate the data.

A post is created by one user, so we say it “belongs to” a user. In Model_Post we can add:

protected static $_belongs_to = array('user');

The user can post multiple blogs, so we add this line:

protected static $_has_many = array('posts');

A quick way to test this works is by firing up the oil console:

Fuel 1.1-rc2 - PHP 5.3.6 (cli) (Sep  8 2011 19:31:33) [Darwin]
>>> $post = Model_Post::find('first');
>>> $post->user->username
admin
-- Ctrl + C to exit

Nice, the relationships work!

Now in the view we can work with $post->user and output their name, so let’s change fuel/app/views/blog/view.php:

<h2><?php echo $post->title ?></h2>

<p>
	<strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>)
	by <?php echo $post->user->username ?>
</p>

<p><?php echo nl2br($post->body) ?></p>

Doing things this way is called lazy loading. What basically happens is that when you ask for $post->user the ORM returns the user object based on the contents of the user_id field. This means to get the post and the first user is two queries, getting the second will be a third, etc and so it can end up being very slow with all these additional queries.

To improve performance you can switch from lazy loading to eager loading which basically tells the ORM you are going to be joining users on so it should do it as part of the first query. This can make for one larger query but the ORM will slice it up nicely for you and you wont notice the difference.

$post = Model_Post::find_by_slug($slug, array('related' => array('user')));

If you look at the query the ORM produces, it will be something like this:

SELECT <code>t0</code>.<code>id</code> AS <code>t0_c0</code>, <code>t0</code>.<code>title</code> AS <code>t0_c1</code>, <code>t0</code>.<code>slug</code> AS <code>t0_c2</code>, <code>t0</code>.<code>summary</code> AS <code>t0_c3</code>, <code>t0</code>.<code>body</code> AS <code>t0_c4</code>, <code>t0</code>.<code>user_id</code> AS <code>t0_c5</code>, <code>t0</code>.<code>created_at</code> AS <code>t0_c6</code>, <code>t0</code>.<code>updated_at</code> AS <code>t0_c7</code>, <code>t1</code>.<code>id</code> AS <code>t1_c0</code>, <code>t1</code>.<code>username</code> AS <code>t1_c1</code>, <code>t1</code>.<code>password</code> AS <code>t1_c2</code>, <code>t1</code>.<code>group</code> AS <code>t1_c3</code>, <code>t1</code>.<code>email</code> AS <code>t1_c4</code>, <code>t1</code>.<code>last_login</code> AS <code>t1_c5</code>, <code>t1</code>.<code>login_hash</code> AS <code>t1_c6</code>, <code>t1</code>.<code>profile_fields</code> AS <code>t1_c7</code>, <code>t1</code>.<code>created_at</code> AS <code>t1_c8</code>, <code>t1</code>.<code>updated_at</code> AS <code>t1_c9</code> FROM (SELECT <code>t0</code>.<code>id</code>, <code>t0</code>.<code>title</code>, <code>t0</code>.<code>slug</code>, <code>t0</code>.<code>summary</code>, <code>t0</code>.<code>body</code>, <code>t0</code>.<code>user_id</code>, <code>t0</code>.<code>created_at</code>, <code>t0</code>.<code>updated_at</code> FROM <code>posts</code> AS <code>t0</code> ORDER BY <code>t0</code>.<code>id</code> ASC LIMIT 1) AS <code>t0</code> LEFT JOIN <code>users</code> AS <code>t1</code> ON (<code>t0</code>.<code>user_id</code> = <code>t1</code>.<code>id</code>) WHERE (<code>t0</code>.<code>slug</code> = 'women-love-guys-who-use-fuelphp') ORDER BY <code>t0</code>.<code>id</code> ASC

At first this might look insane, but the ORM knows exactly what is going on. Using this approach in the past I have reduced a application from running 300+ queries on a busy page (very slow) down to about 2 (very fast).


Step 8 - Adding Comments

Lots of “make a blog” tutorials stop before they get to comments which I think is a major under-sight. Every blog needs comments and we want to add them quickly so we can go and do something more fun, so we can use code generation to build the admin interface:

$ oil generate admin comments name:string email:string website:string message:text post_id:int
	Creating migration: /Users/phil/Sites/blog/fuel/app/migrations/003_create_comments.php
	Creating model: /Users/phil/Sites/blog/fuel/app/classes/model/comment.php
	Creating controller: /Users/phil/Sites/blog/fuel/app/classes/controller/admin/comments.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/index.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/view.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/create.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/edit.php
	Creating view: /Users/phil/Sites/blog/fuel/app/views/admin/comments/_form.php

$ oil refine migrate
Migrated app:default to latest version: 3.

Comments will need some similar tweaks as Post did so make those then we set up the relationships.

Model_User

protected static $_has_many = array('posts', 'comments');
protected static $_belongs_to = array('user');

Model_Post

protected static $_belongs_to = array('user');
protected static $_has_many = array('comments');

Model_Comment

protected static $_belongs_to = array('post', 'user');

Add a comment through the interface the cheating way, by going to http://localhost/blog/public/admin/comments/create and entering one

Comment admin

Now we can test the relationship in the console again:

Fuel 1.1-rc2 - PHP 5.3.6 (cli) (Sep  8 2011 19:31:33) [Darwin]
>>> Model_Post::find(1)->comments
array (
  1 =>
  Model_Comment::__set_state(array(
   '_is_new' => false,
   '_frozen' => false,
   '_data' =>
  array (
  'id' => '1',
  'name' => 'Phil Sturgeon',
  'email' => 'email@philsturgeon.co.uk',
  'website' => 'http://philsturgeon.co.uk/',
  'message' => 'This is an epic article.',
  'post_id' => '1',
  'created_at' => '1322931744',
  'updated_at' => '1322931744',
  ),
   '_original' =>
  array (
  'id' => '1',
  'name' => 'Phil Sturgeon',
  'email' => 'email@philsturgeon.co.uk',
  'website' => 'http://philsturgeon.co.uk/',
  'message' => 'This is an epic article.',
  'post_id' => '1',
  'created_at' => '1322931744',
  'updated_at' => '1322931744',
  ),
   '_data_relations' =>
  array (
  ),
   '_original_relations' =>
  array (
  ),
   '_view' => NULL,
   '_iterable' =>
  array (
  ),
  )),
)

Output of an array of ORM objects is a little verbose, but at least we can see the data. This means the relationship is working nicely, so let’s modify the ORM query in the blog controllers action_view() method to include comments:

$post = Model_Post::find_by_slug($slug, array('related' => array('user', 'comments')));

Now update the blog view to output the comments and have a form to add more:

<h2><?php echo $post->title ?></h2>

<p>
	<strong>Posted: </strong><?php echo date('nS F, Y', $post->created_at) ?> (<?php echo Date::time_ago($post->created_at)?>)
	by <?php echo $post->user->username ?>
</p>

<p><?php echo nl2br($post->body) ?></p>

<hr />

<h3 id="comments">Comments</h3>

<?php foreach ($post->comments as $comment): ?>

	<p><?php echo Html::anchor($comment->website, $comment->name) ?> said "<?php echo $comment->message?>"</p>

<?php endforeach; ?>

<h3>Write a comment</h3>

<?php echo Form::open('blog/comment/'.$post->slug) ?>

<div class="row">
	<label for="name">Name:</label>
	<div class="input"><?php echo Form::input('name'); ?></div>
</div>

<div class="row">
	<label for="website">Website:</label>
	<div class="input"><?php echo Form::input('website'); ?></div>
</div>

<div class="row">
	<label for="email">Email:</label>
	<div class="input"><?php echo Form::input('email'); ?></div>
</div>

<div class="row">
	<label for="message">Comment:</label>
	<div class="input"><?php echo Form::textarea('message'); ?></div>
</div>

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

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

This code will output all comments in a very basic style followed by a really simple form using Twitter Bootstrap markup. I’m sure you can whip up some styling for the comments section.

Comment form

We can see the comment is being output and any that are added will also be put in. So the next and final stage in the process is to get comments saved.

The line with Form::open('blog/comment/'.$post->slug) will set the action to blog/comment/women-love-guys-who-use-fuelphp which means Controller_Blog needs a new method action_comment($slug) which should look something like this:

public function action_comment($slug)
{
	$post = Model_Post::find_by_slug($slug);

	// Lazy validation
	if (Input::post('name') AND Input::post('email') AND Input::post('message'))
	{
		// Create a new comment
		$post->comments[] = new Model_Comment(array(
			'name' => Input::post('name'),
			'website' => Input::post('website'),
			'email' => Input::post('email'),
			'message' => Input::post('message'),
			'user_id' => $this->current_user->id,
		));

		// Save the post and the comment will save too
		if ($post->save())
		{
			$comment = end($post->comments);
			Session::set_flash('success', 'Added comment #'.$comment->id.'.');
		}
		else
		{
			Session::set_flash('error', 'Could not save comment.');
		}

		Response::redirect('blog/view/'.$slug);
	}

	// Did not have all the fields
	else
	{
		// Just show the view again until they get it right
		$this->action_view($slug);
	}
}

Summary

This article skipped a few things like how to set up a pretty URL instead of localhost/blog/public and how to use form validation in the model or the controller, but all of this can be found in the FuelPHP Documentation. I planned to touch on things like File Uploads and Migrations a little more but again this is all documented already.

You should have enough code now to pick apart and play with, and whatever project you choose to work on with FuelPHP already has a blog now – so throw up a splash page, design it and you are ready to make the next SquareFaceTwitBook.

Add Comment

Discussion 110 Comments

Comment Page 1 of 21 2
  1. jannik says:

    oh my god. the timing on this tutorial is just… as if you did it just for me :O

    thanks so much!^.^

  2. Tim says:

    FuelPHP is AWESOME

  3. Martin says:

    great, useful thankx

  4. sirfilip says:

    Always a pleasure reading Phil’s posts.

  5. You bad bad man,
    It’s been a while since I feel the urge to learn a new framework. I’ve been using Codeigniter for a year now, and I have a installation of Fuel sitting on my computer ready to be on a date with me for like a month. :P

    I’ve never had that “urge” and looks like this post was my awake up call.

    I’ll be trying all this back sorcery over xmas, and when I’m ready I’ll use on a real project.

    cheers and nice post Phill,
    Marco Monteiro

  6. kankaro says:

    Great article post….. thanks a lot :D I’ve already bookmarked it… for future projects :D

  7. David says:

    I’m so glad to see that more developers are beginning to build more applications using Fuel! It really is an AMAZING framework.

  8. Ryan Dennler says:

    I’m just now getting into Fuel and this is perfect, thanks for the great tutorial!

  9. Kris says:

    Nothing works. Oil is creating apps with old version of fuel. Admin generator and Bootstrap are missing.

  10. Brett says:

    Following these instructions, getting to

    $ oil generate admin posts title:string slug:string summary:text body:text user_id:int

    does not work for me – ‘admin’ is not one of the ‘generate’ commands:

    Usage:
    php oil [g|generate] [controller|model|migration|scaffold|views] [options]

    What am I missing?

  11. wburningham says:

    I’m trying to run:

    oil generate admin posts …

    oil isn’t recognizing admin as a valid parameter in its usage. Any ideas?

    Usage:
    php oil [g|generate] [controller|model|migration|scaffold|views] [options]

  12. wburningham says:

    I’ve been exclusively using CodeIgniter for all my PHP development. I am interested in learning more about FuelPHP.

    What are the main differences/similarities between CodeIgniter and FuelPHP? Is there are article that already compares the two?

    @Phil
    I think you have helped develop both. I’m interested in hearing your thoughts.

    Thanks.

    • kapil verma says:

      If you don’t mind, I’d like to pitch in what I think about codeigniter and fuel

      Both are dead easy to use, have great docs etc . but fuel is pretty much php5.3 (has some features which CI doesn’t have but CI has so many ‘sparks’ that its easy to make CI a full-featured framework).

      What being more php5.3 means is mainy proper, cleaner OOP, no $this-> everywhere, feels a lot cleaner and intutuive. A beginner who knows the basics of OOP can understand whats going on in fuel than in CI (very few CI noobs would know that the whole framework is one object).

      Namespaces for modules help in better modular architecture .. plus the HMVC thing is there (I haven’t leveraged much on that though yet).

      What it lacks is psr-0 .. which, IMO, would make it dead simple to add on libraries from symfony2 or lithium to fuel and also provide much better way to build your app(no more _ in classnames, more intutive aliasing, etc) … from what i know, thats coming in 2.0

      IMO, if you are at least a decent CI dev .. switch to fuel, it’ll only make you a better dev

  13. wafto says:

    I have some issue while running oil generate admin posts… There is no generator for admin.

    • Author

      You need to be using the very latest 1.1/develop. I was expecting RC2 to be released by now as the RC1 was about 6 weeks ago… Hopefully it will be out soon but you can still use this tutorial on the develop code.

  14. This is really a hard job, but here you explain it very nice, which is making it simple :) thanks for Posting this tutorial.

  15. Said says:

    This is really awesome! It also supports (H)MVC )))) Rails like development )))

  16. pierlo says:

    Thanks for the great article. FuelPHP is really exciting.

    I’m currently in a love affaire with FuelCMS ( getfuelcms.com ) and while reading of stuff like the oil command makes me wet my pants, I’d still suggest you folks to check it out as well…

  17. Zack says:

    This framework looks and reads eerily similar to Kohana

  18. jesus says:

    Fuel is one of the framework i have been looking for when i was moving from code igniter.
    At the end, i have to choose yiiframework.

    The most downside of fuel is that requieres php 5.3. That’s a good thing, but my currents servers are running on php 5.2 :(

    • Tom Schlick says:

      PHP 5.3 has been out for a while now and allows FuelPHP to take advantage of awesome stuff like namespaces. The benefits of requiring 5.3 really outweigh the downsides. If you are running on a shared server I would poke around and see if there is a config to change your php version. As I said before, 5.3 has been out a while now so most hosts have upgraded or at least given the option to upgrade.

  19. begs says:

    I was exclusively developing in Codeigniter the last years. I tried Kohana but that wasn’t it for me.
    But now, looking at your tutorial about FuelPHP, it seems that this is really the things i’m missing on Codeigniter.

    I’ll give it a try!

    Thanks for your tutorial!

  20. Vincent says:

    For those having problems using oil to generate the admin part: it seems like the author was using a more recent version of oil than the oil installer as used in the tutorial installs. Get oil from Github for the most recent version which is able to generate admin structures.

    You also have to manually install Twitter’s Bootstrap files into your assets folder.

  21. Niklas says:

    I like it. Just migrated from CI to Fuel. ^^

  22. daGrevis says:

    No offence, but ORM cannot possibly know what’s going on under the hood!

    • Jesus says:

      Great thing about php open source code is that. If you want to know how the framework does something, you just have to take a look in the source code.

    • Author

      Can you explain that viewpoint? I entered a very large ORM query to show an example of how ORM can handle more than we can, because I sure as hell don’t know whats happening there but the ORM does.

      Bad ORM’s have given ORM’s in general a bad name. Used correctly and in the right instances an ORM can generate quite efficient queries. As long as intelligent caching, field mapping and relationships are handled efficiently an ORM can be incredibly useful and not cause a bottleneck in your application like everyone assumes.

      It would be great if you could read my article on my blog:

      http://philsturgeon.co.uk/blog/2011/06/misconceptions-about-orms

      • daGrevis says:

        P.S. I’m not saying that FuelPHP sucks… no-no. I say that ORM sucks when primary goal is application speed. It’s not sin to use ORM for relatively small projects like blog or guest book.

      • Author

        Of course I have read the “ORM is an Anti-Pattern”, I linked to it at the top of my article before I ripped all of its points to shreds.

        If your one and only goal is absolute speed then of course using a system that does more is slower, but that does not mean ORM’s have their place.

        Your comment “ORM cannot possibly know what’s going on under the hood” is pretty different from you saying “ORM’s are not as quick at executing as native SQL” which is of course true, but if it saves me 20% of my development time then I can employ somebody later to make the app more efficient when we get the first round of investment or when the whole thing sells for a million.

        I’m not trying to shout you down, but ORM’s ARE useful when used correctly.

    • kapil says:

      IMO, given the number of apps being built today, and the speed one is required to build them at, ORMs save a lot of time and let you do stuff quicker. Again, IMO, if your app becomes big enough that ORM is the deciding factor in its scalability, the time required to re-write the model layer wouldn’t be a waste. So I’d say that ORM is a nice thing to have..

  23. Brayan says:

    Seems like the wordpress plugin is escaping the underscores ? LOL

    $view->set\_global(‘users’, Arr::assoc_to_keyval(Model\_User::find(‘all’), ‘id’, ‘username’));

    Anyway.. great article :-)

  24. Johan says:

    Wow Phil! Thank you very much for this solid tutorial! I downloaded FuelPHP last night and walked through the tut to get acquainted with the framework. And I’m sold, and will be using it for a project I’m just starting! See you at the FuelPHP forums, I’m signing up!

    Cheers!

  25. Dmitry Seredinov says:

    Nice post, Phil, thanks.
    But one minor issue that i’ve discovered: in the Controller_Base.php instead of
    View::set_global(‘current_user’, $this->current_user);
    needs to be used
    View::set_global(‘current_user’, $this->current_user[0]);

    Reason: original line produces the exception

    Notice!

    ErrorException [ Notice ]: Trying to get property of non-object

    APPPATH/views/admin/template.php @ line 46:
    45: username
    47: ?>

    because we have passed to global current_user array instead of user’s object itself (contains in current_user[0]).

    Anyway, thanks for tutorial.

    • Author

      You need to be using the latest 1.1/develop for all the branches as unfortunately our tag of RC2 which contains some tweaks I made while writing this article got put back. Our release manager is sorting some stuff out but its out of my control.

  26. Kawsar says:

    Why i should use FuelPHP?Is it better then CodeIgniter?

    • Author

      Better is a basically a non-word when it comes to this stuff. CodeIgniter is a lightweight framework, FuelPHP is a full-stack framework. We’ve got ORM, Migrations, etc and a lot more stuff bundled in but sometimes you need more portability so a 5.3 framework won’t be for you on that project.

      I use both frameworks, and Rails, and Sinatra and occasionally make some workers with Python. Get yourself a tool-belt, don’t just use one for everything all the time.

  27. Umar says:

    After being one of the “naysayers” and then taking up FuelPHP and giving it a spin, I have to say I am loving it so far. Phil, Dan, Jelmer and the rest of the Fuel team have done a great job at writing excellent, clean and readable code for the framework. Thank you for this excellent tutorial. =)

  28. admin section building is important for development time. I’m currently building with Yii framework. It’s faster and easy.

  29. Militis says:

    There appears to be a step missing after the admin generation:

    oil refine migrate

  30. be 10 games says:

    Stop by the IRC too! #fuelphp on freenode. There are always a bunch of people there to help out if you have any issues!

  31. Drazen Mokic says:

    You took many good things from Rails, like migrations and command-line model and controller generation and atm i am learning rails because exactly of those things.

    Now i am not sure why i should or if i should learn rails when some of the good parts are now available in a PHP framework.

    Phil, is there a reason you don`t just use Rails instead of PHP, is it because you are just used more to PHP than to Rails or is there another reason?

    • Author

      Learn as many frameworks as you can in the time you have available. If you end up loving Rails then carry on.

      I use Rails for some projects and FuelPHP for others, depending on the requirements of the job. It used to be I’d use Rails for projects that required REALLY good Social integration for which I’d use the get OmniAuth, but then I needed similar behaviour in PHP so I ported it and built NinjAuth.

      https://github.com/happyninjas/fuel-ninjauth

      Now I mainly use Rails for things that involve a lot of worker processes around it, but I am starting to see some tools pop up around FuelPHP that will make that less important for me too.

      Like I said it’s about building a toolbelt, not just using the one tool. Learn as much as you can and apply it to other places and it will make you better overall.

  32. David says:

    Where did you come up with the find() method? I can’t find it in the FuelPHP documentation.

  33. Jorge says:

    Great tutorial, thanks so much. I was waiting for it since I read the first part. I’m trying to get an understanding about when to use viewmodels, can you please talk a little bit about that? Also, an example about when to use the H in HMVC would be great.

    I’m going to use FuelPHP for my next project, with MongoDB and Sphinx mixed all together. I believe you’ve made a great job. Thanks a lot and keep the good work :)

    • Author

      A ViewModel comes in useful when you find yourself collating lots of data from different sources over and over again in the controller. A controller is used to say “I would like this data from these places to go into this view”, but if that logic is being repeated in multiple places a ViewModel can be used to group it together.

      This is a brilliant feature actually suggested to the FuelPHP team by zombor from the Kohana team, showing that cooperation between framework developers is one of the best things for us as a community. :)

  34. John Wright says:

    Everything is working great now. I really like FuelPHP and this admin tutorial is a great feature and starting point!

    Thanks Phil!

  35. I’m not completely sure what “ORM cannot possibly know what’s going on under the hood!” means, but if it means what I think it means it’s just dead wrong.

    inKWell uses Flourish which has an ORM which not only knows what’s going on under the hood, but uses it pretty intelligently. Essentially it can “reflect” your database schema with no configuration required. Not only is this useful for dynamically understanding relationships, but it also means that joins can and will be fairly automated.

    Indeed, if you register a callback to be executed during ORM operations, the callback can go so far as to accept the related records which were joined to the record in question.

    To get an idea of just how powerful and FAST this is and what it means for the development process, check out the video for inKWell which shows setting up a database and using the ORM:

    http://vimeo.com/21050748

  36. Merdj says:

    Hello Phil,

    thanks for the part two of your tutorial, the first part indeed helped me with my first project but the project didn’t push through due to various reasons.

    but now, v1.1 is released and I want to start again. I am following your tutorial but i am facing a problem, this error appeared when I am in the part of issuing this command.

    php oil refine migrate

    I am using windows 7, uniformserver as wamp stack.

    and this is the error I am receiving:

    invalid data source name in COREPATH/classes/database/pdo/connection.php

    please help and big thanks for you and to the team of FuelPHP developer

    God bless

    • Tim says:

      I got the same error and by changing “localhost” to “127.0.0.1″ in the db config it worked

      • merdj says:

        Hello Tim,

        I did that too, changing it to localhost but no avail at all. What WAMP stack do you use? Mine is uniformserver, maybe this is the problem? or could I ask the source from you, IF it is ok with you… big thanks

      • Tim says:

        Actually I use XAMPP on Windows and MAMP on Mac and both work so I don’t think that is the problem. Sorry but I am also new to PHP and FuelPHP also, I don’t know exactly what might the problem be in your case. Maybe someone else can suggest you something else.

  37. oax says:

    when I do this command

    oil generate admin posts title:string slug:string summary:text body:text user_id:int

    I’ve got the following error

    Usage:
    php oil [g|generate] [controller|model|migration|scaffold|views] [options]

    Runtime options:
    -f, [--force] # Overwrite files that already exist
    -s, [--skip] # Skip files that already exist
    -q, [--quiet] # Supress status output
    -t, [--speak] # Speak errors in a robot voice

    Description:
    The ‘oil’ command can be used to generate MVC components, database migrations
    and run specific tasks.

    Examples:
    php oil generate controller [ | |..]
    php oil g model [: |: |..]
    php oil g migration [: |: |..]
    php oil g scaffold [: |: |..]
    php oil g scaffold/template_subfolder [: |: |..]

    Note that the next two lines are equivalent:
    php oil g scaffold …
    php oil g scaffold/default …

    Documentation:
    http://fuelphp.com/docs/packages/oil/generate.html

    does anyone know where does it com from?

    • Tim says:

      Did you make sure you got the latest final version (v1.1). Because that error happened in the RC

      • Author

        Correct, that error would pop up if you were using 1.1 RC1 but it’s all fine in 1.1 final.

      • merdj says:

        @Phil, Tim,

        Yes I did, I did download the latest version to be sure, still the error doesn’t go away.

        Could it be possible Phil for you to give me the source of this sample? including the entire fuel package, just to be sure that I will working the original sample from yours.

        In the old version, I got no problem at all, migration runs perfectly. I was able to make our company’s website, without any issues at all. Now, with the new one, I want to use the PDO connection. Our company is using SQL Server, so they might encourage me to use to connect to SQL server.

        Please help me… thanks

  38. VMobile says:

    This is all what I need to start FUEL .. This upgrade is really the best reasons to fully develop on fuel.

    My only concern was that there were a lot of deprecated functions which my old fuel app had to be rewritten to accommodate … But it’s all for the best so I can’t complain

    This is the best framework for me … Good job Phil!!

  39. Great tutorial and apparently fuel is quite powerful, includes many very interesting functions of others frameworks like scaffolding similar to rails and pattern design implemented well.

    We want more!!!

  40. coax says:

    thanks for our help, you were right I had a wrong version V1.1_rc,

  41. coax says:

    I can’t log to the admin, I think the trouble is coming from my table ‘users’ I made it myself, I have mamp and can’t fix the bug on it for ‘oil refine migrate’ even with the troubleshooting doc, so can you please give me an example or a screenshot of your table to be sure i make it the good way
    thanks

  42. Jake Smith says:

    @Phil

    I apologize if it has been mentioned or is documented, but…..

    1. Does Fuel follow PSR-0 for autoloading?
    2. How tightly coupled is the ORM, can one choose to use doctrine or propel easily?

    • Author

      Hey Jake,

      FuelPHP 1.x does not use PSR-0 which at the time was chosen for various reasons: http://fuelphp.com/blog/2011/04/classnames-autoloading-namespaces

      It looks like we’ll be changing that for FuelPHP 2.0 so we can start to move towards more standard code, which should mean people can just dump Zend or PEAR code in without any worries about how it works.

      Basically the only difference is that we need to Uppercase the first letter of each class filename but there are a few extra things to think about.

      the autoloader can be modified and extended anyway so PSR-0 is not difficult to work in, we just don’t want to break peoples applications in a minor update. :)

    • Author

      I missed part of the answer.

      ORM is not coupled with the core AT ALL anywhere. You can delete the ORM package and carry on using FuelPHP with Doctrine or Propel, etc.

      If you want to use Oil scaffolding and code generation you will need to make different templates, but thats easy to do too.

  43. Bretticus says:

    Wow! FuelPHP is getting more and more mature. The ORM stuff looks awesome. Keep up the great work guys!

  44. Paul says:

    thanks for these tutorials phil, keep them coming, i learn by example (urg) so these are helping me alot…

  45. Fabulous, now I have everything I need to start implementing FuelPHP in our company’s workflow.

    Keep up the amazing work guys, and I’ll definitely go hang in the forum a bit more and give it a go to start contributing to this amazing project!

    I started learning Rails, but being a Front-End Web Developer this was getting a little too much for my needs. FuelPHP fills the gap and borrows what I loved in Rails.

    Looking forward for the next tut!

  46. By the way Phil, concerning the tutorial:

    In the admin controller (controller/admin.php), the set_flash notice for welcoming the user doesn’t output the username. I get this in the log:

    Error – 2011-12-17 17:01:40 –> 8 – Undefined variable: current_user in (…)controller/admin.php on line 39

    Could you just point me how to fix this? I tried referencing with $this->current_user->username, since it gets set in the before() function in the base controller, but I get the same error.

    Thanks!

  47. Stunt says:

    Simple is better ! It’s always been ! just check around and see successes

    Working with CLI to generate code is not the way I like to code.
    Fuel is doing step backward like CakePHP

    I like code with Codeigniter it has better concept and very logical MVC and OOP and better to understand.
    I hope Fuel change the way and get away from the way that CakePHP choose to go.

    Fuel give me choise how to work but first it emphasis the Complex !
    Tools should be simple to use but be able to change for doing complex and hard things.
    I learn many things from Fuel source code but I like continue using Codeigniter.

    • Author

      Code Generation is not a step back, it is providing you with a second option. As I have explicitly stated multiple times you do not HAVE to use code generation but you can if you want to.

      I would much rather be given an option than not be offered the chance to do something, especially if the a large percentage of the community have stated they want that option. :)

    • Ian says:

      @Stunt,

      I hated the cli and code generation until I figured out it’s an extra and not a requirement. It does make it more difficult for a beginner to understand the code and workings of the framework though. I picked up enough CI to make a complete site and even start extending the framework on my own but I don’t think it was because CI is any easier. I think it is because I was manually typing all the code while going through the tutorials.

      Still, this is some great info and I’m picking up on it. Just a little slower than with the CI tuts.

      I would like it if CI also adds a cli option for code generation and migrations and it would be great if they put scaffolding back in. I just don’t like using it for learning.

      • Author

        CodeIgniter never had Scaffolding. I have been using CodeIgniter since 2007 and while they had a feature CALLED Scaffolding, it wasn’t the Scaffolding that everyone thinks it is. It was litterally just a temporary interface for a single table, which could not be used in production for anything. It was insecure, unwieldily and pointless.

        Also, CodeIgniter has migrations and has had them for a year.

        I really think I have gone to great lengths to make the command line usage be obviously optional in the FuelPHP documentation, all my articles and this tutorial especially. I went with using Oil for the majority of the tutorial to show off the power of it all but mainly because this tutorial would have been 50 pages of just code.

        The idea here is that you can use the generated code as examples to look through, then start using bits of that to build your own sites. You can just look at the documentation if you want to build everything from scratch and learn how it all works.

  48. Brad Dunn says:

    Fantastic Tutorial! I did notice that after running the code in step 5 you need to run “oil refine migrate” to update the DB with a new table to handle posts before the posts page works properly.

    Although this makes sense to me now, I was totally in the dark while reading your tutorial as to why my app wasn’t working properly. Just thought I’d point out that you might want to explicitly say that in step 5.

Comment Page 1 of 21 2

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.