The Model class is the bread and butter of CakePHP applications. By
creating a CakePHP 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.

CakePHP’s model class files go in /app/Model, and the file
we’ll be creating will be saved to /app/Model/Post.php. The
completed file should look like this:

classPostextendsAppModel{}

Naming conventions are very important in CakePHP. By naming our model
Post, CakePHP can automatically infer that this model will be used
in the PostsController, and will be tied to a database table called
posts.

Note

CakePHP will dynamically create a model object for you if it
cannot find a corresponding file in /app/Model. This also means
that if you accidentally name your file wrong (for example, post.php
or posts.php instead of Post.php), CakePHP will not recognize
any of your settings and will use the defaults instead.

For more on models, such as table prefixes, callbacks, and
validation, check out the Models chapter of the
Manual.

Next, we’ll create a controller for our posts. The controller is
where all the controlling logic for post interaction will happen. In a
nutshell, it’s the place where you play with the models and get
post-related work done. We’ll place this new controller in a file
called PostsController.php inside the /app/Controller
directory. Here’s what the basic controller should look like:

Now, let’s add an action to our controller. Actions often represent
a single function or interface in an application. For example, when
users request www.example.com/posts/index (which is the same
as www.example.com/posts/), they might expect to see a listing of
posts. The code for that action would look something like this:

By defining function index()
in our PostsController, users can 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.

Warning

You may be tempted to name your controllers and actions a certain
way to obtain a certain URL. Resist that temptation. Follow CakePHP
conventions (capitalization, plural names, etc.) and create readable,
understandable action names. You can map URLs to your code using
“routes” covered later on.

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

To learn more about CakePHP’s controllers, check out the
Controllers chapter.

Now that we have our data flowing to our model, and our application
logic and flow defined by our controller, let’s create a view for
the index action we created above.

CakePHP views are just presentation-flavored fragments that fit inside
an application’s layout. For most applications, they’re HTML mixed
with PHP, but they may end up as XML, CSV, or even binary data.

A layout is presentation code that is wrapped around a view.
Multiple layouts can be defined, and you can switch between
them, but for now, let’s just use the default.

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

CakePHP’s view files are stored in /app/View inside a folder
named after the controller to which they correspond. (We’ll have to create
a folder named ‘Posts’ in this case.) To format this post data into a
nice table, our view code might look something like this

You might have noticed the use of an object called $this->Html.
This is an instance of the CakePHP HtmlHelper class. CakePHP
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 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 URLs in CakePHP, it is recommended that you use the
array format. This is explained in more detail in the section on
Routes. Using the array format for URLs allows you to take
advantage of CakePHP’s reverse routing capabilities. You can also
specify URLs relative to the base of the application in the form of
/controller/action/param1/param2.

At this point, 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 (which link a post’s title to a URL /posts/view/some_id),
you were probably informed by CakePHP that the action hadn’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 in the
PostsController now:

The set() call should look familiar. Notice we’re using
findById() rather than find('all') because we only want
a single post’s information.

Notice that our view action takes a parameter: the ID of the post
we’d like to see. This parameter is handed to the action through
the requested URL. If a user requests /posts/view/3, then the value
‘3’ is passed as $id.

We also do a bit of error checking to ensure that a user is actually
accessing a record. If a user requests /posts/view, we will throw a
NotFoundException and let the CakePHP ErrorHandler take over. We
also perform a similar check to make sure the user has accessed a
record that exists.

Now let’s create the view for our new ‘view’ action and place it in
/app/View/Posts/view.ctp

$this->request->is() takes a single argument, which can be the
request METHOD (get, put, post, delete) or some request
identifier (ajax). It is not a way to check for specific posted
data. For instance, $this->request->is('book') will not return true
if book data was posted.

Note

You need to include the FlashComponent - and FlashHelper - in
any controller where you will use it. If necessary, include it in
your AppController.

Here’s what the add() action does: if the HTTP method of the
request was POST, it tries to save the data using the Post model. If for some
reason it doesn’t save, it just renders the view. This gives us a
chance to show the user validation errors or other warnings.

Every CakePHP request includes a CakeRequest object which is accessible using
$this->request. The request object contains useful information regarding the
request that was just received, and can be used to control the flow of your application.
In this case, we use the CakeRequest::is() method to check that the request is a HTTP POST request.

When a user uses a form to POST data to your application, that
information is available in $this->request->data. You can use the
pr() or debug() functions to print it out if you want to see
what it looks like.

We use the FlashComponent’s FlashComponent::success()
method to set a message to a session variable to be displayed on the page after
redirection. In the layout we have
FlashHelper::render() which displays the
message and clears the corresponding session variable. The
controller’s Controller::redirect function
redirects to another URL. The param array('action'=>'index')
translates to URL /posts (that is, the index action of the posts controller).
You can refer to Router::url() function on the
API to see the formats in which you can specify a
URL for various CakePHP functions.

Calling the save() method will check for validation errors and
abort the save if any occur. We’ll discuss how those errors are
handled in the following sections.

We call the create() method first in order to reset the model
state for saving new information. It does not actually create a record in the
database, but clears Model::$id and sets Model::$data based on your database
field defaults.

We use the FormHelper to generate the opening tag for an HTML
form. Here’s the HTML that $this->Form->create() generates:

<formid="PostAddForm"method="post"action="/posts/add">

If create() is called with no parameters supplied, it assumes
you are building a form that submits via POST to the current controller’s
add() action (or edit() action when id is included in
the form data).

The $this->Form->input() method is used to create form elements
of the same name. The first parameter tells CakePHP which field
they correspond to, and the second parameter allows you to specify
a wide array of options - in this case, the number of rows for the
textarea. There’s a bit of introspection and automagic here:
input() will output different form elements based on the model
field specified.

The $this->Form->end() call generates a submit button and ends
the form. If a string is supplied as the first parameter to
end(), the FormHelper outputs a submit button named accordingly
along with the closing form tag. Again, refer to
Helpers for more on helpers.

Now let’s go back and update our /app/View/Posts/index.ctp
view to include a new “Add Post” link. Before the <table>, add
the following line:

The $validate array tells CakePHP how to validate your data
when the save() method is called. Here, I’ve specified that
both the body and title fields must not be empty. CakePHP’s
validation engine is strong, with a number of pre-built rules
(credit card numbers, email addresses, etc.) and flexibility for
adding your own validation rules. For more information,
check the Data Validation.

Now that you have your validation rules in place, use the app to
try to add a post with an empty title or body to see how it works.
Since we’ve used the FormHelper::input() method of the
FormHelper to create our form elements, our validation error
messages will be shown automatically.

This action first ensures that the user has tried to access an existing record.
If they haven’t passed in an $id parameter, or the post does not
exist, we throw a NotFoundException for the CakePHP ErrorHandler to take care of.

Next the action checks whether the request is either a POST or a PUT request. If it is, then we
use the POST data to update our Post record, or kick back and show the user
validation errors.

If there is no data set to $this->request->data, we simply set it to the
previously retrieved post.

This view outputs the edit form (with the values populated), along
with any necessary validation error messages.

One thing to note here: CakePHP will assume that you are editing a
model if the ‘id’ field is present in the data array. If no ‘id’ is
present (look back at our add view), CakePHP will assume that you are
inserting a new model when save() is called.

Next, let’s make a way for users to delete posts. Start with a
delete() action in the PostsController:

publicfunctiondelete($id){if($this->request->is('get')){thrownewMethodNotAllowedException();}if($this->Post->delete($id)){$this->Flash->success(__('The post with id: %s has been deleted.',h($id)));}else{$this->Flash->error(__('The post with id: %s could not be deleted.',h($id)));}return$this->redirect(array('action'=>'index'));}

This logic deletes the post specified by $id, and uses
$this->Flash->success() to show the user a confirmation
message after redirecting them on to /posts. If the user attempts to
do a delete using a GET request, we throw an Exception. Uncaught exceptions
are captured by CakePHP’s exception handler, and a nice error page is
displayed. There are many built-in Exceptions that can
be used to indicate the various HTTP errors your application might need
to generate.

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

Using postLink() will create a link that uses
JavaScript to do a POST request to delete our post. Allowing content to be
deleted using GET requests is dangerous, as web crawlers could accidentally
delete all your content.

Note

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

For some, CakePHP’s default routing works well enough. Developers
who are sensitive to user-friendliness and general search engine
compatibility will appreciate the way that CakePHP’s URLs map to
specific actions. So we’ll just make a quick change to routes in
this tutorial.

By default, CakePHP responds to a request for the root of your site
(e.g., http://www.example.com) using its PagesController, rendering
a view called “home”. Instead, we’ll replace this with our
PostsController by creating a routing rule.

CakePHP’s routing is found in /app/Config/routes.php. You’ll want
to comment out or remove the line that defines the default root
route. It looks like this:

This line connects the URL ‘/’ with the default CakePHP home page.
We want it to connect with our own controller, so replace that line
with this one:

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

This should connect users requesting ‘/’ to the index() action of
our PostsController.

Note

CakePHP also makes use of ‘reverse routing’. If, with the above
route defined, you pass
array('controller'=>'posts','action'=>'index') to a
function expecting an array, the resulting URL used will be ‘/’.
It’s therefore a good idea to always use arrays for URLs, as this
means your routes define where a URL goes, and also ensures that
links point to the same place.

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

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

If you need help, there are many ways to get the help you need - please see the Where to Get Help page.
Welcome to CakePHP!