Thursday, December 27, 2007

The Cake Blog Tutorial

Introduction
Welcome to Cake! You're probably checking out this tutorial because you want to learn more about how Cake works. Its our aim to increase productivity and make coding more enjoyable: we hope you'll see this as you dive into the code.

This tutorial will walk you through the creation of a simple blog application. We'll be getting and installing Cake, creating and configuring a database, and creating enough application logic to list, add, edit, and delete blog posts.
Here's what you'll need:

A running web server. We're going to assume you're using Apache, though the instructions for using other servers should be very similar. We might have to play a little with the server configuration, but most folks can get Cake up and running without any configuration at all.

A database server. We're going to be using mySQL in this tutorial. You'll need to know enough about SQL in order to create a database: Cake will be taking the reigns from there.

Basic PHP knowledge. The more object-oriented programming you've done, the better: but fear not if you're a procedural fan.

Finally, you'll need a basic knowledge of the MVC programming pattern. A quick overview can be found in Chapter "Basic Concepts", Section 2: The MVC Pattern. Don't worry: its only a half a page or so.

Let's get started!

Section 2
Getting Cake
First, let's get a copy of fresh Cake code.

To get a fresh download, visit the CakePHP project at Cakeforge: http://cakeforge.org/projects/cakephp/ and download the stable release.

You can also checkout/export a fresh copy of our trunk code at: https://svn.cakephp.org/repo/trunk/cake/1.x.x.x/

Regardless of how you downloaded it, place the code inside of your DocumentRoot. Once finished, your directory setup should look something like the following:

/path_to_document_root
/app
/cake
/vendors
.htaccess
index.php
VERSION.txtNow might be a good time to learn a bit about how Cake's directory structure works: check out Chapter "Basic Concepts", Section 3: Overview of the Cake File Layout.

Section 3
Creating the Blog Database
Next, lets set up the underlying database for our blog. Right now, we'll just create a single table to store our posts. We'll also throw in a few posts right now to use for testing purposes. Execute the following SQL statements into your database:

/* First, create our posts table: */
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);

/* Then insert some posts for testing: */
INSERT INTO posts (title,body,created)
VALUES ('The title', 'This is the post body.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('A title once again', 'And the post body follows.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('Title strikes back', 'This is really exciting! Not.', NOW());

The choices on table and column names are not arbitrary. If you follow Cake's database naming conventions, and Cake's class naming conventions (both outlined in Appendix "Cake Conventions"), you'll be able to take advantage of a lot of free functionality and avoid configuration. Cake is flexible enough to accomodate even the worst legacy database schema, but adhering to convention will save you time.

Check out Appendix "Cake Conventions" for more information, but suffice it to say that naming our table 'posts' automatically hooks it to our Post model, and having fields called 'modified' and 'created' will be automagically managed by Cake.

Section 4
Cake Database Configuration
Onward and upward: let's tell Cake where our database is and how to connect to it. This will be the first and last time you configure anything.

A copy of Cake's database configuration file is found in /app/config/database.php.default. Make a copy of this file in the same directory, but name it database.php.

The config file should be pretty straightforward: just replace the values in the $default array with those that apply to your setup. A sample completed configuration array might look something like the following:

var $default = array('driver' => 'mysql',
'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => 'cakeBlog',
'password' => 'c4k3-rUl3Z',
'database' => 'cake_blog_tutorial' );
Once you've saved your new database.php file, you should be able to open your browser and see the Cake welcome page. It should also tell you that your database connection file was found, and that Cake can successfully connect to the database.

Section 5
A Note On mod_rewrite
Occasionally a new user will run in to mod_rewrite issues, so I'll mention them marginally here. If the Cake welcome page looks a little funny (no images or css styles), it probably means mod_rewrite isn't functioning on your system. Here are some tips to help get you up and running:

Make sure that an .htaccess override is allowed: in your httpd.conf, you should have a section that defines a section for each Directory on your server. Make sure the AllowOverride is set to All for the correct Directory.

Make sure you are editing the system httpd.conf rather than a user- or site-specific httpd.conf.

For some reason or another, you might have obtained a copy of CakePHP without the needed .htaccess files. This sometimes happens because some operating systems treat files that start with '.' as hidden, and don't copy them. Make sure your copy of CakePHP is from the downloads section of the site or our SVN repository.

Make sure you are loading up mod_rewrite correctly! You should see something like LoadModule rewrite_module libexec/httpd/mod_rewrite.so and AddModule mod_rewrite.c in your httpd.conf.


If you don't want or can't get mod_rewrite (or some other compatible module) up and running on your server, you'll need to use Cake's built in pretty URLs. In /app/config/core.php, uncomment the line that looks like:

define ('BASE_URL', env('SCRIPT_NAME'));
This will make your URLs look like www.example.com/index.php/controllername/actionname/param rather than www.example.com/controllername/actionname/param.

Section 6
Create a Post Model
The model class is the bread and butter of CakePHP applications. By creating a Cake model that will interact with our database, we'll have the foundation in place needed to do our view, add, edit, and delete operations later.

Cake's model class files go in /app/models, and the file we will be creating will be saved to /app/models/post.php. The completed file should look like this:

/app/models/post.php

Because of the way the class and file are named, this tells Cake that you want a Post model available in your PostsController that is tied to a table in your default database called 'posts'.

The $name variable is always a good idea to add, and is used to overcome some class name oddness in PHP4.

For more on models, such as table prefixes, callbacks, and validation, check out Chapter "Models".

Section 7
Create a Posts Controller
Next we'll create a controller for our posts. The controller is where all the logic for post interaction will happen, and its also where all the actions for this model will be found. You should place this new controller in a file called posts_controller.php inside your /app/controllers directory. Here's what the basic controller should look like:

/app/controllers/posts_controller.php

Now, lets add an action to our controller. When users request www.example.com/posts, this is the same as requesting www.example.com/posts/index. Since we want our readers to view a list of posts when they access that URL, the index action would look something like this:

/app/controllers/posts_controller.php (index action added)
set('posts', $this->Post->findAll());
}
}

?>
Let me explain the action a bit. By defining function index() in our PostsController, users can now access the logic there by requesting www.example.com/posts/index. Similarly, if we were to define a function called foobar(), users would be able to access that at www.example.com/posts/foobar.

The single instruction in the action uses set() to pass data to the view (which we'll create next). The line sets the view variable called 'posts' equal to the return value of the findAll() method of the Post model. Our Post model is automatically available at $this->Post because we've followed Cake's naming conventions.

To learn more about Cake's controllers, check out Chapter "Controllers".

Section 8
Creating Post Views
Now that we have our database connected using our model, and our application logic and flow defined by our controller, let's create a view for the index action we defined above.

Cake views are just HTML and PHP flavored fragments that fit inside an application's layout. Layouts can be defined and switched between, but for now, let's just use the default.

Remember in the last section how we assigned the 'posts' variable to the view using the set() method? That would hand down data to the view that would look something like this:

// print_r($posts) output:

Array
(
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => The title
[body] => This is the post body.
[created] => 2006-03-08 14:42:22
[modified] =>
)
)
[1] => Array
(
[Post] => Array
(
[id] => 2
[title] => A title once again
[body] => And the post body follows.
[created] => 2006-03-08 14:42:23
[modified] =>
)
)
[2] => Array
(
[Post] => Array
(
[id] => 3
[title] => Title strikes back
[body] => This is really exciting! Not.
[created] => 2006-03-08 14:42:24
[modified] =>
)
)
)
Cake's view files are stored in /app/views inside a folder named after the controller they correspond to (we'll have to create a folder named 'posts' in this case). To format this post data in a nice table, our view code might look something like this:

/app/views/posts/index.thtml

Blog posts



















IdTitleCreated

link($post['Post']['title'], "/posts/view/".$post['Post']['id']); ?>

Hopefully this should look somewhat simple.

You might have noticed the use of an object called $html. This is an instance of the HtmlHelper class. Cake comes with a set of view 'helpers' that make things like linking, form output, JavaScript and Ajax a snap. You can learn more about how to use them in Chapter "Helpers", but what's important to note here is that the link() method will generate an HTML link with the given title (the first parameter) and URL (the second parameter).

When specifying URL's in Cake, you simply give a path relative to the base of the application, and Cake fills in the rest. As such, your URL's will typically take the form of /controller/action/id.

Now you should be able to point your browser to http://www.example.com/posts/index. You should see your view, correctly formatted with the title and table listing of the posts.

If you happened to have clicked on one of the links we created in this view (that link a post's title to a URL /posts/view/some_id), you were probably informed by Cake that the action hasn't yet been defined. If you were not so informed, either something has gone wrong, or you actually did define it already, in which case you are very sneaky. Otherwise, we'll create it now:

/app/controllers/posts_controller.php (view action added)
set('posts', $this->Post->findAll());
}

function view($id = null)
{
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
}

?>
The set() call should look familiar. Notice we're using read() rather than findAll() because we only really want a single post's information.

Notice that our view action takes a parameter. This parameter is handed to the action by the URL called. If a user requests /posts/view/3, then the value '3' is passed as $id.

Now let's create the view for our new 'view' action and place it in /app/views/posts/view.thtml.

/app/views/posts/view.thtml



Created:




Verify that this is working by trying the links at /posts/index or manually requesting a post by accessing /posts/view/1.

Section 9
Adding Posts
reading from the database and showing us the posts is fine and dandy, but let's allow for the adding of new posts.

First, start with the add() action in the PostsController:

/app/controllers/posts_controller.php (add action added)
set('posts', $this->Post->findAll());
}

function view($id)
{
$this->Post->id = $id;
$this->set('post', $this->Post->read());

}

function add()
{
if (!empty($this->data))
{
if ($this->Post->save($this->data))
{
$this->flash('Your post has been saved.','/posts');
}
}
}
}

?>
Let me read the add() action for you in plain English: if the form data isn't empty, try to save the post model using that data. If for some reason it doesn't save, give me the data validation errors and render the view showing those errors.

When a user uses a form to POST data to your application, that information is available in $this->params. You can pr() that out if you want to see what it looks like. $this->data is an alias for $this->params['data'].

The $this->flash() function called is a controller function that flashes a message to the user for a second (using the flash layout) then forwards the user on to another URL (/posts, in this case). If DEBUG is set to 0 $this->flash() will redirect automatically, however, if DEBUG > 0 then you will be able to see the flash layout and click on the message to handle the redirect.

Calling the save() method will check for validation errors and will not save if any occur. There are several methods available so you can check for validation errors, but we talk about the validateErrors() call in a bit, so keep that on the back burner for a moment while I show you what the view looks like when we move on to the section about data validation.

Section 10
Data Validation
Cake goes a long way in taking the monotony out of form input validation. Everyone hates coding up endless forms and their validation routines, and Cake makes it easier and faster.

To take advantage of the validation features, you'll need to use Cake's HtmlHelper in your views. The HtmlHelper is available by default to all views at $html.

Here's our add view:

/app/views/posts/add.thtml

Add Post


url('/posts/add')?>" method=post>


Title:
input('Post/title', array('size' => '40'))?>
tagErrorMsg('Post/title', 'Title is required.') ?>



Body:
textarea('Post/body', array('rows'=>'10')) ?>
tagErrorMsg('Post/body', 'Body is required.') ?>



submit('Save') ?>



As with $html->link(), $html->url() will generate a proper URL from the controller and action we have given it. By default, it prints out a POST form tag, but this can be modified by the second parameter. The $html->input() and $html->textarea() functions spit out form elements of the same name. The first parameter tells Cake which model/field they correspond to, and the second param is for extra HTML attributes (like the size of the input field). Again, refer to Chapter "Helpers" for more on helpers.

The tagErrorMsg() function calls will output the error messages in case there is a validation problem.

If you'd like, you can update your /app/views/posts/index.thtml view to include a new "Add Post" link that points to www.example.com/posts/add.

That seems cool enough, but how do I tell Cake about my validation requirements? This is where we come back to the model.

/app/models/post.php (validation array added)
VALID_NOT_EMPTY,
'body' => VALID_NOT_EMPTY

);
}

?>
The $validate array tells Cake how to validate your data when the save() method is called. The values for those keys are just constants set by Cake that translate to regex matches (see /cake/libs/validators.php). Right now Cake's validation is regex based, but you can also use Model::invalidate() to set your own validation dynamically.

Now that you have your validation in place, use the app to try to add a post without a title or body to see how it works.

Section 11
Deleting Posts
Next, let's make a way for users to delete posts. Start with a delete() action in the PostsController:

/app/controllers/posts_controller.php (delete action only)
function delete($id)
{
$this->Post->del($id);
$this->flash('The post with id: '.$id.' has been deleted.', '/posts');
}
This logic deletes the post specified by $id, and uses flash() to show the user a confirmation message before redirecting them on to /posts.

Because we're just executing some logic and redirecting, this action has no view. You might want to update your index view to allow users to delete posts, however.

/app/views/posts/index.thtml (add and delete links added)

Blog posts


link('Add Post', '/posts/add'); ?>




















IdTitleCreated

link($post['Post']['title'], '/posts/view/'.$post['Post']['id']);?>
link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>

This view code also uses the HtmlHelper to prompt the user with a JavaScript confirmation dialog before they attempt to delete a post.

Section 12
Editing Posts
So... post editing: here we go. You're a Cake pro by now, so you should have picked up a pattern. Make the action, then the view. Here's what the edit action of the Posts Controller would look like:

/app/controllers/posts_controller.php (edit action only)
function edit($id = null)
{
if (empty($this->data))
{
$this->Post->id = $id;
$this->data = $this->Post->read();
}
else
{
if ($this->Post->save($this->data['Post']))
{
$this->flash('Your post has been updated.','/posts');
}
}
}
This checks for submitted form data. If nothing was submitted, go find the Post and hand it to the view. If some data has been submitted, try to save the Post model (or kick back and show the user the validation errors).

The edit view might look something like this:

/app/views/posts/edit.thtml

Edit Post


url('/posts/edit')?>" method=post>
hidden('Post/id'); ?>


Title:
input('Post/title', array('size' => '40'))?>
tagErrorMsg('Post/title', 'Title is required.') ?>



Body:
textarea('Post/body', array('rows'=>'10')) ?>
tagErrorMsg('Post/body', 'Body is required.') ?>



submit('Save') ?>



This view ouputs the edit form (with the values populated), and the necessary error messages (if present). One thing to note here: Cake will assume that you are edititing a model if the 'id' field is present and exists in a currently stored model. If no 'id' is present (look back at our add view), Cake will assume that you are inserting a new model when save() is called.

You can now update your index view with links to edit specific posts:

/app/views/posts/index.thtml (edit links added)

Blog posts


link("Add Post", "/posts/add"); ?>



















IdTitleCreated

link($post['Post']['title'], '/posts/view/'.$post['Post']['id']);?>
link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>
link('Edit', '/posts/edit/'.$post['Post']['id']);?>


Section 13
Routes
This part is optional, but helpful in understanding how URLs map to specific function calls in Cake. We're only going to make a quick change to routes in this tutorial. For more information, see Chapter "Configuration", Section 3: Routes Configuration.

Cake's default route will take a person visiting the root of your site (i.e. http://www.example.com) to the PagesController, and render a view called home. Rather than do that, we'll want users of our blog application to go to our soon-to-be-created PostsController.

Cake's routing is found in /app/config/routes.php. You'll want to comment out or remove the line that looks like this:

$Route->connect ('/', array('controller'=>'pages', 'action'=>'display', 'home'));
This line connects the URL / with the default Cake home page. We want it to connect with our own controller, so add a line that looks like this:

$Route->connect ('/', array('controller'=>'posts', 'action'=>'index'));
This should connect users requesting '/' to the index() action of our soon-to-be-created PostsController.

Section 14
Conclusion
Creating applications this way will win you peace, honor, women, and money beyond even your wildest fantasies. Simple, isn't it? Keep in mind that this tutorial was very basic. Cake has many more features to offer, and is flexible in ways we didn't wish to cover here. Use the rest of this manual as a guide for building more feature-rich applications.

Now that you've created a basic Cake application you're ready for the real thing. Start your own project, read the rest of the Manual and API.

Artikel yang Berkaitan

0 komentar:

Post a Comment