Creating a guestbook with CakePHP part 2

In my first post I showed how to setup your development environment, create your tables and use the CakePHP command line utility to bake the models, controllers and views. I’m now going to expand upon this bare bones guestbook by adding in some authentication.

Adding authentication

If you’ve looked at the controllers we baked, you’ll see they extend AppController. AppController is a handy place to put code which will effect all controllers. If your project does not have it’s own app controller, CakePHP uses it’s default one. In our case the app controller is a handy place to configure our authentication. We’ll start by creating the file ‘app/app_controller.php’. Note we do not place it in ‘app/controllers’. Here’s what we’ll put in that file:

<?php
class AppController extends Controller {
    var $components = array('Auth', 'Session');

    function beforeFilter() {
        $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
        $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
        $this->Auth->loginRedirect = array('controller' => 'posts', 'action' => 'adminindex');
    }
}
?>

Here we’ve declared we will be using the Auth component. This is a handy CakePHP component which will handle the authentication functionality for us.  The beforeFilter() function is called before each controller action, here we setup where our login action will be and where it should redirect to once the user has logged in.

We now need to create the login action on the users controller. Open up ‘app/controllers/users_controller.php’. Inside the UsersController class, add the following functions:

	function login() {
		if ($this->Session->read('Auth.User')) {
			$this->Session->setFlash('You are now logged in');
			$this->redirect('/', null, false);
		}
    }

	function logout() {
		$this->Session->setFlash('You are now logged out');
		$this->redirect($this->Auth->logout());
	}

We now have login and logout actions. Each action in our controller requires a view. When we created our app controller we set the logout view to be the login screen, in the code above we redirect to this when the user logs out. This means we only need to add a view for the login screen.

Create the file ‘app/views/users/login.ctp’ and enter the code below:

<?php
	$session->flash('auth');
	echo $form->create('User', array('action' => 'login'));
	echo $form->inputs(array(
		'username',
		'password'
		));
	echo $form->end('Login');
?>

The first thing we do here is to display any messages we set in the controller. When we refer to $session we are actually referring to an instance of SessionHelper created for us by CakePHP. We then use FormHelper to start the login form. We tell it the model this form is for and the action the form should submit to. We then use the FormHelper inputs function to create our input boxes for username and password. We could go further and define custom labels, but we’ll just stick with the defaults.

You should be able to visit http://localhost/guestbook/users/login. Note that if you now try and visit any page, you will be redirected to login. By default CakePHP authentication locks down all controller actions. However we need to create a user to be able to login. To get around this, add this temporary function to users_controller.php:

	function beforeFilter() {
		$this->Auth->allow('add');
    }

This tells CakePHP to allow anyone to access this action, even if they aren’t logged in. Go ahead and visit http://localhost/guestbook/users/add. Add a user, making sure to keep a note of the details you enter. Now remove the code we just added and go to http://localhost/guestbook/users/login. You should be able to login successfully.

We now have our guestbook protected by authentication, however we have everything protected. We need to loosen the restrictions. The two things we want anyone to be able to do are view the guestbook and add a new post. To do this we simply add the following into the PostsController class found at ‘/app/controllers/posts’:

	function beforeFilter() {
		$this->Auth->allow('index', 'add');
    }

One final change we need to make is to change the main page. At the moment we’re asked to login when we visit http://localhost/guestbook. We want this URL to go to the list of guestbook posts. There are a number of ways to do this but arguably the simplist is to change routes.php. You can find this file in ‘app/config’.

Replace the line:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

With:

Router::connect('/', array('controller' => 'posts', 'action' => 'index', 'home'));

That’s all the functionality complete. Logged in users can do anything and guests can view and add a post to our guestbook. You’ve probably noticed however that it doesn’t look much like a guestbook. Normally a guestbook would have separate admin and public interfaces, here ours looks like one big admin console. Luckily CakePHP has an elegant solution in the form of layouts. At the moment CakePHP is using the default layout file found at ‘cake/libs/view/layouts/default.ctp’. Copy this file to ‘app/views/layouts’. The default layout is quite adequate for the admin area, so we’ll just make some simple modifications.

Changing the layout

First of all, you may have noticed the SQL dump which appears at the bottom of each page, lets tidy things up by removing it. Open ‘app/views/layouts/default.ctp’, find and remove the line:

<?php echo $this->element('sql_dump'); ?>

There’s also some text which reads “CakePHP: the rapid development php framework” in a couple of places. I’m going to change these to “Guestbook admin console”, except the one in the footer which refers to the CakePHP logo.

That’s our admin view sorted, onto the public view. Create the file public.ctp in the ‘app/views/layouts folder’. I’m going to base the look of the guestbook on Perhypex:Guest. Here’s what you should put in the public.ctp file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<?php echo $this->Html->charset(); ?>
	<title>
		Guestbook:
		<?php echo $title_for_layout; ?>
	</title>
	<?php
		echo $this->Html->meta('icon');
		echo $this->Html->css('public');
		echo $scripts_for_layout;
	?>
</head>
<body>
	<div id="container">
		<div id="header">
			My Guestbook
		</div>
		<div id="page_container">
			<?php echo $this->Session->flash(); ?>
			<?php echo $content_for_layout; ?>
		</div>
		<div id="footer">
			Thanks for visiting!
		</div>
	</div>
</body>
</html>

This is a simple layout in which we tell CakePHP to use the public css file. We’ll create that file now. In ‘app/webroot/css’ create the file public.css with the following content:

body {
background-color:#ffffff;
margin:0px;
padding:0px;
font-family:Arial, Helvetica, sans-serif;
color:#000000;
}

#header {
background-color:#990000;
color:#ffffff;
text-align:center;
height:80px;
font-size:30pt;
padding-top:10px;
}

/* Contains all the comments */
#page_container {
width:750px;
margin-right:auto;
margin-left:auto;
}

/* Makes elements float to the left */
.align_left {
float:left;
}

/* Makes elements float to the right */
.align_right {
float:right;
}

/* Contains the view or sign guestbook and return to site options */
.options {
padding:30px 0 30px 0;
}

/* The style for options links */
.options a{
font-size:16pt;
}

/* Box which contains the comment */
.comment {
border:2px solid #990000;
margin:10px 0 10px 0;
}

/* Appears at the top of the comment box with the name and date */
.comment_header {
background-color:#990000;
padding:5px;
font-size:16pt;
color:#ffffff;
overflow:auto;
}

/* contains extra fields such as the location */
.extra_fields {
background-color:#c3c5c3;
color:#000000;
padding:10px;
}

/* Contains the persons actual comment */
.comment_body {
padding:10px;
}

/* Section which contains the page numbers */
.page_number {
text-align:center;
padding:10px;
}

/* Appears at the bottom with a link back to perhypex:guest */
#footer {
text-align:center;
padding:20px;
color:#b82929;
}

/* Global style for the links on the page */
a {
color:#990000;
font-weight:bold;
text-decoration:underline;
}

/* How visited links should change */
a:visited {
font-weight:normal;
}

/* How a link should change when the cursor is over it */
a:hover {
text-decoration:none;
}

/* Style for the form the user fills in */
#comment_form {
margin-top:20px;
}

/* Style for the input labels */
label {
font-weight:bold;
}

/* Style for the area in which the user enters their comment */
textarea {
font-family:Arial, Helvetica, sans-serif;
}

Now we just need to tell the index and add functions to use this layout. Add the following as the first line of the index and add functions inside ‘app/controllers/posts_controller.php’:

$this->layout = 'public';

We now just need to customise the add and index action views.

Replace the contents of ‘app/views/posts/add.ctp’ with the following:

<div class="options">
	<span class="align_left">
		<?php echo $this->Html->link(__('View the guestbook', true), array('action' => 'index')); ?>
	</span>
</div>

<div class="posts form">
	<?php echo $this->Form->create('Post');?>
		<fieldset>
			<legend><?php __('Sign the guestbook'); ?></legend>
		<?php
			echo $this->Form->input('name');
			echo $this->Form->input('body', array('type' => 'textarea'));
		?>
		</fieldset>
	<?php echo $this->Form->end(__('Submit', true));?>
</div>

We now need to change the ‘app/views/posts/index.ctp’ file. The current layout of this file will be useful as an admin index, so rename it to adminindex.ctp. Next create the file index.ctp and add the following content:

<div class="posts index">

	<div class="options">
		<span class="align_left">
			<?php echo $this->Html->link(__('Sign the guestbook', true), array('action' => 'add')); ?>
		</span>
		<span class="align_right">
			<?php echo $this->Paginator->sort('Sort by date posted', 'created'); ?>
		</span>
	</div>

	<?php
	foreach ($posts as $post):?>
		<div class="comment">
			<div class="comment_header">
				<span class="align_left"><?php echo $post['Post']['name']; ?></span>
				<span class="align_right"><?php echo date("F dS, Y", strtotime($post['Post']['created'])); ?></span>
			</div>
			<div class="comment_body">
				<?php echo $post['Post']['body']; ?>
			</div>
			<?php
			if($post['Post']['modified'] != $post['Post']['created']) { ?>
				<div class="extra_fields">
					Edited by the guestbook owner on
					<?php
					echo date("F dS, Y", strtotime($post['Post']['modified']));
					?>
				</div>
			<?php
			}
			?>
		</div>
	<?php endforeach; ?>

	<p>
	<?php
	echo $this->Paginator->counter(array(
	'format' => __('Page %page% of %pages%', true)
	));
	?>	</p>

	<div class="paging">
		<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
	 | 	<?php echo $this->Paginator->numbers();?>
 |
		<?php echo $this->Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?>
	</div>
</div>

Add a few posts and see how it now looks. You may notice one minor problem: the posts are listed from oldest to newest, not exactly how a guestbook works. CakePHP offers a simple way to customise this though. Open up ‘app/controllers/posts_controller.php’. Below

var $name = 'Posts';

add the following:

var $paginate = array(
		'limit' => 10,
		'order' => array(
			'Post.created' => 'desc')
		);

Here we’ve said that we want to view 10 posts per page and by the created date descending.

We’re very nearly done, the only thing we are missing is the action to view the admin index page. Unlike the public page, this page will contain the links to edit and delete posts.

Inside ‘app/controllers/posts_controller.php’, add the following function:

	function adminIndex() {
		$this->Post->recursive = 0;
		$this->set('posts', $this->paginate());
	}

That’s it, our guestbook application is complete!

Posted in Uncategorized | Leave a comment

Creating a guestbook with CakePHP

In this post I will be going over how to develop a simple guestbook application using CakePHP. By the end of this post you will have a functioning guestbook running locally on your machine. By the end of the second post I will have demonstrated how to add authentication and how to create a separate layout for the admin and public areas of the site.

Step 1: set up development environment

The first step is to get a web server with PHP and a database up and running locally. There are many ways to do this but the most popular combination is generally LAMP (Linux Apache MySQL PHP) or WAMP (the same but with Windows). I like to use XAMPP for this as it gives you an instant LAMP/WAMP set up with little to no configuration.

Download XAMPP from http://www.apachefriends.org/en/xampp.html. On Windows extract the archive to C:\, on Linux extract to /opt. Once you’ve extracted XAMPP, you’re ready to go. Run xampp_start.exe on Windows or /opt/lampp/lampp start on Linux.

Visit http://localhost in your browser, you should see the main XAMPP page.

XAMPP main page

XAMPP main page

Step 2: get CakePHP

Get a shiny new copy of CakePHP by visiting CakePHP on github. Extract the resulting archive into XAMPP_INSTALL_DIRECTORY/htdocs. Rename the resulting folder ‘guestbook’. Visit http://localhost/guestbook. You should see the default CakePHP welcome page. It will have some warnings, ignore those for now.

Default CakePHP main page

The default CakePHP main page

Step 3: create the database tables

Next we need to work out what entities we have and what their tables will look like. I’ve chosen a very basic set up with just two tables. One of these will store user details and the other will store the posts. The simplest way to create your database and it’s tables is to visit http://localhost/phpmyadmin in your browser. Under ‘create a new database’ type ‘guestbook’ and click create. Next, click the SQL tab. Here you can execute any raw SQL queries, this is perfect for creating our tables. Paste in the following and click ‘Go’:

CREATE TABLE `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`body` varchar(5000) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`));

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` char(40) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
);

You should now have two tables in your database. At this point it’s important to note some conventions. CakePHP consistently favours convention over configuration. What this means for you is that as long as you play by the rules, you’ll need to do very little configuration. Table names should be plural and all in lower case. By using the field names ‘created’ and ‘modified’ CakePHP will automatically manage these for us.

We need to tell CakePHP where our database is and the login details. Doing this is very simple. Make a copy of the file app/config/database.php.default, call it database.php. Open the file and change the values for $default. Your configuration should be the same as mine, by default the root account will have no password:

var $default = array(
'driver' = 'mysql',
'persistent' = false,
'host' = 'localhost',
'login' = 'root',
'password' = '',
'database' = 'guestbook',
'prefix' = '',
);

Obvious though it is, I should mention that this sort of configuration should only be used for local development. When deploying to a remote server, ensure a secure username and password is used. Using the root account with no password would be extremely bad practice.

Visit http://localhost/guestbook again. You should see that it is now able to connect to your database.

Step 4: create models, controllers and views

Next, we need to create the models, controllers and views. Below is an explanation of what each of these are and where they reside. You may read this or skip ahead and get to all the action.

Models

Each model file represents an entity in our system. So in this case we will have a User and Post entity. Models are placed in app/models. Their file name should be singular and all in lower case, with the ‘.php’ extension. In our case we will have user.php and post.php. By doing this CakePHP will automatically associate these models with our database tables.

Controllers

The controllers are responsible for handling all actions concerned with their views. They get the data from the model and use it to build the view. In CakePHP as with most frameworks the URL of a controller action is: SITE_URL/CONTROLLER_NAME/ACTION. To put this into context, to add a user on our system we will be going to http://localhost/users/add. So here we call the ‘add’ action on the ‘users’ controller. When we go to this URL we will be served the ‘add user’ view. Controllers are placed in app/controllers. Their file names are plural with _controller.php added on. This means our user controller will be called users_controller.php. This important convention means CakePHP automatically associates users_controller.php with our user model and views.

Views

Views are what the user actually sees and interacts with. They are made up of HTML and basic PHP. We don’t really want any application logic going on here but actions such as looping over items and using provided helper classes is fine. Views are kept in app/views. In app/views you should have a separate folder for each entity. In our case we will have a ‘users’ and ‘posts’ folder. Again convention pops it’s head up here, the name of the folder should be lower case and plural. Inside the folder there should be a separate PHP file for each controller action. The name should be the same as the controller action in lower case and with the extension ‘.ctp’. Basic actions are ‘view’, ‘add’, ‘edit’ and ‘delete’. This means our ‘app/views/users’ folder will contain ‘view.ctp’, ‘add.ctp’, ‘edit.ctp’ and ‘delete.ctp’.

Using the CakePHP command line utility

Now for the clever part: CakePHP ships with a command line utility designed to automate the creation of everything I’ve mentioned above. To set this up, you’ll need to add it’s location to your environment variables. I started by copying my ‘guestbook/cake’ folder into ‘C:\xampp’. This ensures that you can still use the cake command line interface if you later move or delete the project.

On Windows, go to computer, right click and select properties. On Vista/7 you will then also need to click ‘Advanced system settings’. Click ‘advanced’ then ‘environment variables’. Edit the path variable, adding ‘C:\xampp\cake\console;’ (or wherever you placed it) to the end of it . OK away the dialogues and you’re ready to roll… I mean er bake.

Open a command line window. Change to the site’s app directory using ‘cd C:\xampp\htdocs\guestbook\app’, if on Linux cd into the relevant directory. Once you’re there, type ‘cake bake all’. Hit return to accept using the default database configuration. You should see the two entities we will be using. Select ’1′ then follow all the prompts, accepting the default each time. Repeat the process but this time select ’2′.

Cake command line utility

Baking with the cake command line utility

You should now find your ‘app/models’, ‘app/controllers’, and ‘app/views’ folders populated. At this point we have most of our functionality in place. We can view, create, edit and delete our guestbook posts and users. We are missing the functionality to stop anyone doing whatever they like though. Try out some of the URLs, for example visit http://localhost/guestbook/users/add and try adding a new user.

I’ll be going over adding the login functionality and changing the layout in the next installment.

Posted in CakePHP, PHP | Tagged , | Leave a comment

Baking with CakePHP

CakePHP: the rapid development PHP framework

PHP is famous for it’s flexibility and almost equally famous for the disaster that flexibility can bring. I learnt PHP some time ago from a book which had no qualms about having MySQL queries thrown in with some HTML and numerous echo statements.

It has to be said though the book was about PHP, to push a certain approach to project layout would be arguably the wrong path in its self. At the end of the day, it’s up to the developer to enforce structure upon themselves when working with PHP. This of course is the problem, many don’t bother or are simply not sure which path to take.

I myself only created a simple guestbook application. This was enough to show me the danger though. Enough so in fact that I scrapped all the code and started again. The spaghetti like structure was hard to work with and making changes invariably often broke something. With my clean slate I introduced an object orientated approach. I was happy, it was so much cleaner. My objects in the database related to PHP classes and I’d taken the time to introduce many little helper classes facilitating features such as automatic sticky forms.

There was an issue of development time though, it took a great deal of time to produce all this clean code. The more I wrote the more I felt I was wasting time implementing general functionality to tidy PHP up. This can be problem when trying to follow software development principles using PHP: the more you write in hope of producing the perfect code base, the more you come to the realization you’re essentially creating your own framework.

With this in mind it’s natural to look around and see what existing frameworks are on offer. After all, despite all your efforts you are essentially reinventing the wheel only to find every step you take there’s another spoke missing.

Wanting to play around with a framework and get some code together, I went looking for what was on offer. After a good look around, I’d narrowed it down to three: CodeIgniter, Zend and CakePHP. All of these follow the Model View Controller pattern.

Now I won’t pretend that I did in depth research into which one was best. Arguably that decision should be made on a per-project basis anyway. CakePHP is the one that really caught my attention though. It grabbed me right after I created a few tables in my database and typed the magic ‘cake bake all’ command. Suddenly I had CRUD (Create, Read, Update, Delete) operations for all my entities, based on the tables. But there is more, it is also clever enough to create views attached to these controller actions. This leaves you with a fully functional skeleton application… and you’ve barely lifted a finger. This automated method of code creation is known as ‘baking’ in CakePHP. On top of all this command line awesomeness is the vast API which provides helpers for many common tasks such as authentication, email, Ajax and form building.

Naturally those wanting to learn PHP should stay away from the frameworks before they take the leap into having half the work done for them. For any PHP developer though, frameworks such as CakePHP are a real blessing. After all, why spend time making everything when you can just bake it?

Posted in CakePHP, PHP | Leave a comment

New website

It’s been some years since I last changed my website. The previous design was created about 3 years ago. It didn’t exactly look out of place by today’s standards: it used XHTML, CSS and PNG images carefully crafted together to meet W3C standards. What was out of place though was the way it worked.

The site was created using PHP. Among other things, It allowed me to create separate files for the layout and combine them all together for a consistent, easy to maintain layout. It did make maintenance much simpler in general. The problem was the site didn’t use a database to store it’s content. Each page existed as a separate file which had to be manually updated.

I wanted to move to a database based solution so I had three options:

  1. Create a complete content management system from the ground up
  2. Use a PHP framework to ease the development of a content management system
  3. Use an existing CMS/blog system

While I like to create things myself, I’ve come to learn that re-inventing the wheel is not generally the way to go. Creating a PHP CMS system from the ground up is a big undertaking. Sure, it may only take a day to pull together some login and posting functionality but there’s much more to a successful CMS system: years of work by hundreds of people more.

Option number two presented me with the same issues. Development speed would be greatly increased, but there’s no getting away from the amount of work involved. One framework I have looked at recently is CakePHP. CakePHP is a rapid development PHP framework that really does what it says on the tin. It’s certainly compelled me to start thinking up some project ideas, though none of these would be a CMS.

WordPress is a platform I’ve had some experience with in the past and suffice to say, I liked what I saw. Anyone who has used WordPress will know just how quick and easy it is to set up. After a couple of days I had themed the site to a design I created previously and put all my content back together.

What I really want to pull away from is the static, rarely updated homepage. I want my site to be active with the technologies I am working with. Using WordPress creates a real incentive for this. Creating and managing posts is all offloaded, all I have to worry about is the content. When it comes to websites, content is king. The easier it is to create and manage content, the easier the content flows onto the site.

I’ll be creating some posts concerning CakePHP soon. It’s a framework I’ve only just begun to learn but it’s simplicity means you can pull together working web applications really fast.

Posted in PHP, wordpress | Leave a comment