Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Getting Started With Cake PHP: Part 2

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

In our last CakePHP tutorial we looked at setting up the CakePHP framework and introduced some of the framework's basic concepts and terminology. Now we turn to illustrating more of CakePHP's rapid development capabilities using a personal blog application as an example. In the next set of tutorials we will build the blog application incrementally so that the basic CakePHP development process is laid out clearly instead of briefly mentioned as in other similar tutorials. In this tutorial we start with a basic authoring authentication component for the example blog application.

Step 1: Defining a Goal

Our goal is to create the components of a personal blog application. By the time we complete the project we will be adding Web 2.0 effects and offering integration with other services to make the application complete. Before we can start our project, however, we need to define a development plan with some sort of feature list to guide us.

Here is a small list of main features we will discuss and include in our finished application:

  • Protected system with, at minimum, capabilities for one author
  • Posting functions will include commenting functionality, provide blog trackbacks, and allow the inclusion of images and uploads
  • Full-text search engine using Sphinx
  • Integration with external services such as Gravatar and Askimet Spam Protection / Spam Management
  • Javascript enhancements including WYSIWYG Editor Capabilities, Ajax Live Search, Ajax Comment Previews, Fast loading Ajax Publish/Edit/Delete functionality and Ajax form validation
  • Integration of the application with Facebook to allow rapid Facebook development (the goals for this feature include sending posts to Facebook's news feed feature and pulling in personal data from the Facebook API to make the blog a little more personal)

In today's article we will focus mainly on the user/author management system because it is the perfect place to learn the basics of controller, model, and view code. Once we learn these basics we can implement them for the other components of the larger system later on.

Without further ado, let's tuck into CakePHP.

Step 2: Models

As mentioned previously, models interact with the framework's underlying database. By default, CakePHP comes with a number of built-in methods to save us from rewriting code to implement common functionality. Along with the expected reading and writing/saving methods, you can also use "magic methods" like findBy<fieldName> which will find rows matching a certain query field. This is a real improvement over using typical "SELECT * FROM" queries.

Our user system for this iteration of the application will be quite basic. Since the main goal is a personal blog we will have only one author at a time. For the sake of extendability, however, we will store the user(s) in a table in case we choose to develop a full blown user/permission system later on, or if we want to manually add more authors. Our basic functionality will allow logging in, logging out, and updating our personal information.

We will do all of this with a small MySQL table implemented by the following CREATE TABLE statement:

CREATE TABLE `authors` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(255) NOT NULL default '',
  `password` varchar(32) NOT NULL default '',
  `name` varchar(255) NOT NULL default '',
  `email` varchar(255) NOT NULL default '',
  `bio` text NOT NULL,
  PRIMARY KEY  (`id`)
)
Table structure

We will also want a basic starting account, so we will also insert a row while we are at it (the username and password for the starting account is test/test):

INSERT INTO `authors` (`username`, `password`, `name`, `email`, `bio`) VALUES ('test', '098f6bcd4621d373cade4e832627b4f6', 'Test', 'test@test.com', 'Hello world...');

The purpose of the table structure is the following:

  • id will be used for the unique user ID when we load the profile.
  • username will be used to login to the management area.
  • password will be an md5 hashed password used for logging in to the management area.
  • name will be used in bylines and the author page. This is the public display name because the user name is not actually shown.
  • email will be used for any future functionality (such as comment notification).
  • bio will be used to store biographical information about an author (such as the author pages seen here on NETTUTS).

Now we actually need to create the model. To do this, create a new file in the /app/models/ folder named author.php with the following contents:

<?php<br />class Author extends AppModel<br />{<br />	var $name = 'Author';<br />}<br />?>
Model Code

The model for this functionality is actually pretty basic. Since the functionality we need, like findByUsername or save is already covered by functions in Model (which is extended by AppModel) we are done with the model side. This blanket file just allows us to interface with the Author table.

In later sections when we start adding post functionality, we may need to extend the models.

Step 3: Views

Views are mainly a mix of HTML and helpers. In other systems we would call these templates. Helpers generate common code or help with common tasks. Some helper types found in CakePHP are HTML helpers and Pagination helpers.

To establish views, create a folder in /app/views/ called authors/ so we can store all our views. Our first view should be called login.thtml with the following contents:

<?php if ($error) { ?>
<h2>Error</h2>
<p class='error'>The username and password do not match. Please try again and double check the entered information.</p>
<?php } ?>

<?php echo $html->formTag('/authors/login/'); ?>

	<label for="username">Username</label>

	<?php 
	echo $html->input('Author/username');
	?>
	
	<label for="password">Password</label>
	<?php
	echo $html->password('Author/password');
	?>

<br />

<?php echo $html->submit("Login"); ?>

</form>

Instead of using <input> tags we are using one of the helpers to generate valid input fields that can be used in our controllers. We also put a bit of error checking at the top of the template in case the user enters a wrong username or password. The error variable is set later in the controller.

Now that our first action has a template behind it, we can move on to the others.

Logging out actually doesn't need its own view because we will just redirect users back to the blog index page and display a quick success message. Updating profile information in user management does need a form, however, so we will need to write a view for that.

Create a template named manage.thtml with the following contents:

<?php if ($error) { ?>
<h2>Error</h2>

<p class='error'>Please make sure all the required information has been filled in.</p>

<?php } ?>

<?php echo $html->formTag('/authors/manage/'); ?>

	<label for="name">Full Name</label>
	<?php 
	echo $html->input('Author/name');
	?>

	<br />
	
	<label for="email">Email</label>
	<?php
	echo $html->input('Author/email');
	?>
	
	<br />
	
	<label for="email">Bio</label>

	<?php
	echo $html->textarea('Author/bio', array('cols'=>'60', 'rows'=>'10'));
	?>
	
<br />

<?php echo $html->submit("Update"); ?>

</form>

This view is very similar to our login form except we are managing some different fields, and we include another helper method ($html->textarea) to generate a text area.

Great! Now that our small set of views are written, we can move on to controllers.

Step 4: Controllers

Controllers act like traffic directors. They accept input, decide what to do with it, and then provide handling instructions to the rest of the system. They are the heart of the application because they take the data from the models and pass it on to correct views to display.

This section will specifically deal with setting and reading a session as well as updating the database. We will also create a "parent" controller from which all of our future controllers will inherit.

First create a file in app/controllers/ named authors_controller.php. Now we will walk through the code step by step.

<?php
class AuthorsController extends AppController
{

	function index( )
	{
		$this->redirect( '/' );
	}
	
    function login( )
    {
        $this->set('error', false);


        if ( ! empty( $this->data ) )
        {
            $author = $this->Author->findByUsername( $this->data['Author']['username'] );

            if( ! empty( $author['Author']['password'] ) && $author['Author']['password'] == md5($this->data['Author']['password']) )
            {
                $this->Session->write( 'Author', $author['Author'] );
				$this->redirect( '/' );
            }
			
            else
                $this->set( 'error', true );
        }
    }

Our index function is pretty basic. For now, we will just redirect to the script index using a built-in CakePHP function named "redirect."

Our login function is a bit more advanced. We first set the error variable to false to stop PHP from throwing back an undefined variable notice. Then we do a check to see if any data has been sent. "$this->data" holds any input data from the login form and comes in the format $this->data['CONTROLLER']['FIELD']. Now we see our magic method "findByUsername". used to find any rows that contain the user name of the user who has just logged in. If we do have a user match, we then compare passwords and write a session using CakePHP's session handler. If there is a problem, we set "error" to true so our view can handle the message. A login system can't get much simpler than that!

Login screen

    function logout( )
    {
        $this->Session->delete( 'Author' );
		$this->flash( 'You have been logged out.', '/' );
    }

The logout function is even simpler. We use CakePHP's session class to totally delete the session, and then we use the "flash" method to redirect. The flash method is a bit different from the redirect method because we are allowed to send a message back to the screen. This becomes useful because we can actually let users know that something has happened.

Note: since we are still in development mode, the flash screen will not automatically redirect. You must click the text to go to the screen. When we are in production mode, this screen would redirect for us.

Logout screen
	function manage()
	{
		$this->set('error', false);
			
		if ( empty( $this->data) )
		{
			$this->Author->id = $this->Session->read( 'Author.id' );
			$this->data = $this->Author->read( );
		}
		
		else
		{
		
			if(  empty ( $this->data['Author']['name'] ) || empty ( $this->data['Author']['email'] ) || empty ( $this->data['Author']['bio'] )  )
			{
				$this->set( 'error', true );
				$this->Author->id = $this->Session->read( 'Author.id' );
				$this->data = $this->Author->read( );
			}
			
			else
			{	
				$this->Author->id = $this->Session->read( 'Author.id' );
				
				if ( $this->Author->save( $this->data['Author'] ) )
					$this->flash( 'Your account information has been updated.', '/authors/manage/' );
			}
		}	
	}


Our most advanced function for this controller is the manage function. A lot of the functionality is implemented using the techniques we just introduced. One thing to note in this function is setting the $this->author->id variable before the save and the read. This tells the model which row to deal with so it doesn't try to save or insert an entire new row. We also deal with more session functionality by reading the id from the hash.

Our final step is to protect the manage page. We only want logged in users to see this page, and we can provide protection with a simple check function. This is a piece of functionality we are also going to need for future screens, so we should store it in a shared place. As mentioned before, all CakePHP controllers inherit from a controller called "AppController" which right now is a blank file sitting in the cake directory..

We will create an application-specific AppController by creating a file named "app_controller.php" in the app/ folder, and insert the following contents:

<?php
class AppController extends Controller
{
	function isLoggedin( )
	{
		if ( ! $this->Session->check( 'Author' ) )
		{
			$this->flash( 'You must be logged in to do that.', '/authors/login' );
			exit;
		}
	}
}
?>

We simply check for the session, and if it is not there we send the user to the login screen. This function can now be used in any controller method.

Our last step is to call the function from our manage function. We open our app/controller/authors_controller.php file and find:

	function manage()
	{
		$this->set('error', false);

and add

$this->isLoggedIn();

right below it.

Manage screen

Step: Testing it Out

The actions can be tested and accessed with the following URLs:

  • http://yoursite.tld/authors/login/
  • http://yoursite.tld/authors/manage/
  • http://yoursite.tld/authors/logout/

The account username is test and the password is test.

Closing

This article was intended to introduce some core CakePHP functions with examples in the context of building a personal blog application. We started with some user/author page functionality to introduce the basic concepts of application development with CakePHP before we move (in the next tutorial) to writing the post controller. That way we will have a better understanding of how everything in the framework fits together. We still have a long way to go before our blog application is complete, so get ready to dive deep into CakePHP so we can get all the blog's post and comment functionality working next time!

Advertisement