You are on page 1of 268

Overview of the Cake File Layout

When you unpack Cake on your server you will find three main folders -
Plain Text View
app
cake
vendors
1. app
2. cake
3. vendors
The cake folder is where the core libraries for Cake lay and you generally won't ever need to
touch it.
The app folder is where your application specific folders and files will go. The separation
between the cake folder and the app folder make it possible for you to have many app folders
sharing a single set of Cake libraries. This also makes it easy to update CakePHP: you just
download the latest version of Cake and overwrite your current core libraries. No need to worry
about overwriting something you wrote for your app.
You can use the vendors directory to keep third-party libraries in. You will learn more about
vendors later, but the basic idea is that you can access classes you've placed in the vendors
directory using Cake's vendor() function.
Let's look at the entire file layout:
Plain Text View
/app
/config - Contains config files for your database, ACL, etc.

/controllers - Controllers go here


/components - Components go here

/index.php - Allows you to deploy cake with /app as the DocumentRoot

/models - Models go here

/plugins - Plugins go here

/tmp - Used for caches and logs

/vendors - Contains third-party libaries for this application

/views - Views go here


/elements - Elements, little bits of views, go here
/errors - Your custom error pages go here
/helpers - Helpers go here
/layouts - Application layout files go here
/pages - Static views go here

/webroot - The DocumentRoot for the application


/css
/files
/img
/js
/cake - Cake's core libraries. Don't edit any files here.

index.php

/vendors - Used for server-wide third-party libraries.

VERSION.txt - Let's you know what version of Cake you're using.


1. /app
2. /config - Contains config files for your database, ACL, etc.
3. /controllers - Controllers go here
4. /components - Components go here
5. /index.php - Allows you to deploy cake with /app as the DocumentRoot
6. /models - Models go here
7.
8. /plugins - Plugins go here
9. /tmp - Used for caches and logs
10./vendors - Contains third-party libaries for this application
11./views - Views go here
12./elements - Elements, little bits of views, go here
13./errors - Your custom error pages go here
14./helpers - Helpers go here
15./layouts - Application layout files go here
16./pages - Static views go here
17./webroot - The DocumentRoot for the application
18./css
19./files
20./img
21./js
22./cake - Cake's core libraries. Don't edit any files here.
23.index.php
24./vendors - Used for server-wide third-party libraries.
25.VERSION.txt - Let's you know what version of Cake you're using.

4 Installing CakePHP
• Edit
• Comments (2)
• History
Introduction
So now you know everything there is to know about the structure and purpose of all the
CakePHP libraries, or you have skipped to this part because you don't care about that stuff and
just want to start playing. Either way, you're ready to get your hands dirty.
This chapter will describe what must be installed on the server, different ways to configure your
server, downloading and installing CakePHP, bringing up the default CakePHP page, and some
troubleshooting tips just in case everything does not go as planned.
Requirements
In order use CakePHP you must first have a server that has all the required libraries and
programs to run CakePHP:
Server Requirements
Here are the requirements for setting up a server to run CakePHP:
1. An HTTP server (like Apache) with the following enabled: sessions, mod_rewrite (not
absolutely necessary but preferred)
2. PHP 4.3.2 or greater. Yes, CakePHP works great in either PHP 4 or 5.
3. A database engine (right now, there is support for MySQL 4+, PostgreSQL and a
wrapper for ADODB).
Installing CakePHP
Getting the most recent stable version
There are a few ways you can secure a copy of CakePHP: getting a stable release from
CakeForge, grabbing a nightly build, or getting a fresh version of code from SVN.
To download a stable version of code, check out the files section of the CakePHP project at
CakeForge by going to http://cakeforge.org/projects/cakephp/.
To grab a nightly, download one from http://cakephp.org/downloads/index/nightly. These nightly
releases are stable, and often include the bug fixes between stable releases.
To grab a fresh copy from our SVN repository, use your favorite SVN client and connect to
https://svn.cakephp.org/repo/trunk/cake/ and choose the version you're after.
Unpacking
Now that you've downloaded the most recent release, place that compressed package on your
web server in the webroot. Now you need to unpack the CakePHP package. There are two ways
to do this, using a development setup, which allows you to easily view many CakePHP
applications under a single domain, or using the production setup, which allows for a single
CakePHP application on the domain.
Setting Up CakePHP
The first way to setup CakePHP is generally only recommended for development environments
because it is less secure. The second way is considered more secure and should be used in a
production environment.
NOTE: /app/tmp must be writable by the user that your web server runs as.
Development Setup
For development we can place the whole Cake installation directory inside the specified
DocumentRoot like this:
Plain Text View

/wwwroot
/cake
/app
/cake
/vendors
.htaccess
index.php
1. /wwwroot
2. /cake
3. /app
4. /cake
5. /vendors
6. .htaccess
7. index.php
In this setup the wwwroot folder acts as the web root so your URLs will look something like this
(if you're also using mod_rewrite):
Plain Text View

<a href="http://www.example.com/cake/controllerName/actionName/param1/param2"
title="Linkification:
http://www.example.com/cake/controllerName/actionName/param1/param2">www.exam
ple.com/cake/controllerName/actionName/param1/param2</a>
1. <a
href="http://www.example.com/cake/controllerName/actionName/param1/para
m2" title="Linkification:
http://www.example.com/cake/controllerName/actionName/param1/param2">www
.example.com/cake/controllerName/actionName/param1/param2</a>

Production Setup
In order to utilize a production setup, you will need to have the rights to change the
DocumentRoot on your server. Doing so, makes the whole domain act as a single CakePHP
application.
The production setup uses the following layout:
Plain Text View

../path_to_cake_install
/app
/config
/controllers
/models
/plugins
/tmp
/vendors
/views
/webroot <-- This should be your new DocumentRoot
.htaccess
index.php
/cake
/vendors
.htaccess
index.php
1. ../path_to_cake_install
2. /app
3. /config
4. /controllers
5. /models
6. /plugins
7. /tmp
8. /vendors
9. /views
10. /webroot <-- This should be your new DocumentRoot
11. .htaccess
12. index.php
13. /cake
14. /vendors
15. .htaccess
16. index.php
Suggested Production httpd.conf
Plain Text View

DocumentRoot /path_to_cake/app/webroot
1. DocumentRoot /path_to_cake/app/webroot
In this setup the webroot directory is acting as the web root so your URLs might look like this (if
you're using mod_rewrite):
Plain Text View

http://www.example.com/controllerName/actionName/param1/param2
1. http://www.example.com/controllerName/actionName/param1/param2
Advanced Setup: Alternative Installation Options
There are some cases where you may wish to place Cake's directories on different places on disk.
This may be due to a shared host restriction, or maybe you just want a few of your apps to share
the same Cake libraries.
There are three main parts to a Cake application:
1. The core CakePHP libraries - Found in /cake
2. Your application code (e.g. controllers, models, layouts and views) - Found in /app
3. Your application webroot files (e.g. images, javascript and css) - Found in /app/webroot
Each of these directories can be located anywhere on your file system, with the exception of the
webroot, which needs to be accessible by your web server. You can even move the webroot
folder out of the app folder as long as you tell Cake where you've put it.
To configure your Cake installation, you'll need to make some changes to
/app/webroot/index.php (as it is distributed in Cake). There are three constants that you'll need
to edit: ROOT, APP_DIR, and CAKE_CORE_INCLUDE_PATH.
1. ROOT should be set to the path of the directory that contains your app folder.
2. APP_DIR should be set to the path of your app folder.
3. CAKE_CORE_INCLUDE_PATH should be set to the path of your Cake libraries folder.
/app/webroot/index.php (partial, comments removed)
Plain Text View

if (!defined('ROOT'))
{
define('ROOT', dirname(dirname(dirname(__FILE__))));
}

if (!defined('APP_DIR'))
{
define ('APP_DIR', basename(dirname(dirname(__FILE__))));
}

if (!defined('CAKE_CORE_INCLUDE_PATH'))
{
define('CAKE_CORE_INCLUDE_PATH', ROOT);
}
1. if (!defined('ROOT'))
2. {
3. define('ROOT', dirname(dirname(dirname(__FILE__))));
4. }
5. if (!defined('APP_DIR'))
6. {
7. define ('APP_DIR', basename(dirname(dirname(__FILE__))));
8. }
9. if (!defined('CAKE_CORE_INCLUDE_PATH'))
10. {
11. define('CAKE_CORE_INCLUDE_PATH', ROOT);
12. }
An example might help illustrate this better. Imagine that I wanted to set up Cake to work with
the following setup:
1. I want my Cake libraries shared with other applications, and placed in /usr/lib/cake.
2. My Cake webroot directory needs to be /var/www/mysite/.
3. My application files will be stored in /home/me/mysite.
Plain Text View

Here's what the file setup looks like:

/home
/me
/mysite <-- Used to be /cake_install/app
/config
/controllers
/models
/plugins
/tmp
/vendors
/views
index.php
/var
/www
/mysite <-- Used to be /cake_install/app/webroot
/css
/files
/img
/js
.htaccess
css.php
favicon.ico
index.php
/usr
/lib
/cake <-- Used to be /cake_install/cake
/cake
/config
/docs
/libs
/scripts
app_controller.php
app_model.php
basics.php
bootstrap.php
dispatcher.php
/vendors
1. Heres what the file setup looks like:
2. /home
3. /me
4. /mysite <-- Used to be /cake_install/app
5. /config
6. /controllers
7. /models
8. /plugins
9. /tmp
10. /vendors
11. /views
12. index.php
13. /var
14. /www
15. /mysite <-- Used to be /cake_install/app/webroot
16. /css
17. /files
18. /img
19. /js
20. .htaccess
21. css.php
22. favicon.ico
23. index.php
24. /usr
25. /lib
26. /cake <-- Used to be /cake_install/cake
27. /cake
28. /config
29. /docs
30. /libs
31. /scripts
32. app_controller.php
33. app_model.php
34. basics.php
35. bootstrap.php
36. dispatcher.php
37. /vendors
Given this type of setup, I would need to edit my webroot index.php file (which should be at
/var/www/mysite/index.php, in this example) to look like the following:
It is recommended to use the 'DS' constant rather than slashes to delimit file paths. This prevents
any 'missing file' errors you might get as a result of using the wrong delimiter, and it makes your
code more portable.
Plain Text View

if (!defined('ROOT'))
{
define('ROOT', DS.'home'.DS.'me');
}

if (!defined('APP_DIR'))
{
define ('APP_DIR', 'mysite');
}

if (!defined('CAKE_CORE_INCLUDE_PATH'))
{
define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cake');
}
1. if (!defined('ROOT'))
2. {
3. define('ROOT', DS.'home'.DS.'me');
4. }
5. if (!defined('APP_DIR'))
6. {
7. define ('APP_DIR', 'mysite');
8. }
9. if (!defined('CAKE_CORE_INCLUDE_PATH'))
10. {
11. define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cake');
12. }
Configuring Apache and mod_rewrite
While CakePHP is built to work with mod_rewrite out of the box, we've noticed that a few users
struggle with getting everything to play nicely on their systems. Here are a few things you might
try to get it running correctly:
1. 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.
2. Make sure you are editing the system httpd.conf rather than a user- or site-specific
httpd.conf.
3. 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.
4. 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.
5. If you are installing Cake into a user directory (http://example.com/~myusername/),
you'll need to modify the .htaccess files in the base directory of your Cake installation,
and in the app/webroot folder. Just add the line "RewriteBase /~myusername/".
6. If for some reason your URLS are suffixed with a long, annoying session ID
(http://example.com/posts/?CAKEPHP=4kgj577sgabvnmhjgkdiuy1956if6ska), you
might also add "php_flag session.trans_id off" to the .htaccess file at the root of your
installation as well.

5 Configuration
• Edit
• Comments (0)
• History
Database Configuration
Your app/config/database.php file is where your database configuration all takes place. A fresh
install doesn't have a database.php, so you'll need to make a copy of database.php.default.
Once you've made a copy and renamed it you'll see the following:
app/config/database.php
Plain Text View

var $default = array('driver' => 'mysql',


'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name',
'prefix' => '');
1. var $default = array('driver' => 'mysql',
2. 'connect' => 'mysql_connect',
3. 'host' => 'localhost',
4. 'login' => 'user',
5. 'password' => 'password',
6. 'database' => 'project_name',
7. 'prefix' => '');
Replace the information provided by default with the database connection information for your
application.
One note about the prefix key: the string you enter there will be prepended to any SQL call that
Cake makes to your database when working with tables. You define it here once so you don't
have to specify it in other places. It also allows you to follow Cake's table naming conventions if
you're on a host that only gives you a single database. Note: for HABTM join tables, you only
add the prefix once: prefix_apples_bananas, not prefix_apples_prefix_bananas.
CakePHP supports the following database drivers:
1. mysql
2. postgres
3. sqlite
4. pear-drivername (so you might enter pear-mysql, for example)
5. adodb-drivername
The 'connect' key in the $default connection allows you to specify whether or not the database
connection will be treated as persistent or not. Read the comments in the database.php.default
file for help on specifying connection types for your database setup.
Your database tables should also follow the following conventions:
1. Table names used by Cake should consist of English words in plural, like "users",
"authors" or "articles". Note that corresponding models have singular names.
2. Your tables must have a primary key named 'id'.
3. If you plan to relate tables, use foreign keys that look like: 'article_id'. The table name is
singular, followed by an underscore, followed by 'id'.
4. If you include a 'created' and/or 'modified' column in your table, Cake will automatically
populate the field when appropriate.
You'll also notice that there is a $test connection setting included in the database.php file. Fill out
this configuration (or add other similarly formatted configurations) and use it in your application
by placing something like:
Plain Text View

var $useDbConfig = 'test';


1. var $useDbConfig = 'test';
Inside one of your models. You can add any number of additional connection settings in this
manner.
Global Configuration
CakePHP's global configuration can be found in app/config/core.php. While we really dislike
configuration files, it just had to be done. There are a few things you can change here, and the
notes on each of these settings can be found within the comments of the core.php file.
DEBUG: Set this to different values to help you debug your application as you build it.
Specifying this setting to a non-zero value will force Cake to print out the results of pr( ) and
debug( ) function calls, and stop flash messages from forwarding automatically. Setting it to 2 or
higher will result in SQL statements being printed at the bottom of the page.
Also when in debug mode (where DEBUG is set to 1 or higher), Cake will render certain
generated error pages, i.e. "Missing Controller," "Missing Action," etc. In production mode,
however (where DEBUG is set to 0), Cake renders the "Not Found" page, which can be
overridden in app/views/errors/error404.thtml.
CAKE_SESSION_COOKIE: Change this value to the name of the cookie you'd like to use for
user sessions in your Cake app.
CAKE_SECURITY: Change this value to indicate your preferred level of sessions checking.
Cake will timeout sessions, generate new session ids, and delete old session files based on the
settings you provide here. The possible values are:
1. high: sessions time out after 20 minutes of inactivity, and session id's are regenerated on
each request
2. medium: sessions time out after 200 minutes of inactivity
3. low: sessions time out after 600 minutes of inactivity
CAKE_SESSION_SAVE: Specify how you'd like session data saved. Possible values are:
1. cake: Session data is saved in tmp/ inside your Cake installation
2. php: Session data saved as defined in php.ini
3. database: Session data saved to database connection defined by the 'default' key.
Routes Configuration
"Routing" is a pared-down pure-PHP mod_rewrite-alike that can map URLs to
controller/action/params and back. It was added to Cake to make pretty URLs more configurable
and to divorce us from the mod_rewrite requirement. Using mod_rewrite, however, will make
your address bar look much more tidy.
Routes are individual rules that map matching URLs to specific controllers and actions. Routes
are configured in the app/config/routes.php file. They are set-up like this:
Route Pattern
Plain Text View

<?php
$Route->connect (
'URL',
array('controller'=>'controllername',
'action'=>'actionname', 'firstparam')
);
?>
1. <?php
2. $Route->connect (
3. 'URL',
4. array('controller'=>'controllername',
5. 'action'=>'actionname', 'firstparam')
6. );
7. ?>
Where:
1. URL is the regular expression Cake URL you wish to map,
2. controllername is the name of the controller you wish to invoke,
3. actionname is the name of the controller's action you wish to invoke,
4. and firstparam is the value of the first parameter of the action you've specified.
Any parameters following firstparam will also be passed as parameters to the controller action.
The following example joins all the urls in /blog to the BlogController. The default action will be
BlogController::index().
Route Example
Plain Text View

<?php
$Route->connect ('/blog/:action/*', array('controller'=>'Blog',
'action'=>'index'));
?>
1. <?php
2. $Route->connect ('/blog/:action/*', array('controller'=>'Blog',
'action'=>'index'));
3. ?>
A URL like /blog/history/05/june can then be handled like this:
Route Handling in a Controller
Plain Text View

<?php
class BlogController extends AppController
{
function history ($year, $month=null)
{
// .. Display appropriate content
}
}
?>
1. <?php
2. class BlogController extends AppController
3. {
4. function history ($year, $month=null)
5. {
6. // .. Display appropriate content
7. }
8. }
9. ?>
The 'history' from the URL was matched by :action from the Blog's route. URL elements
matched by * are passed to the active controller's handling method as parameters, hence the
$year and $month. Called with URL /blog/history/05, history() would only be passed one
parameter, 05.
The following example is a default CakePHP route used to set up a route for
PagesController::display('home'). Home is a view which can be overridden by creating the file
/app/views/pages/home.thtml.
Setting the Default Route
Plain Text View

<?php
$Route->connect ('/', array('controller'=>'Pages', 'action'=>'display',
'home'));
?>
1. <?php
2. $Route->connect ('/', array('controller'=>'Pages', 'action'=>'display',
'home'));
3. ?>
Advanced Routing Configuration: Admin Routing and Webservices
There are some settings in /app/config/core.php you can take advantage of in order to organize
your application and craft URLs that make the most sense to you and your users.
The first of these is admin routing. If your application has a ProductsController as well as a
NewsController, you might want to set up some special URLs so users with administrative
privileges can access special actions in those controllers. To keep the URLs nice and easy to
read, some people prefer /admin/products/add and /admin/news/post to something like
/products/adminAdd and /news/adminPost.
To enable this, first, uncomment the CAKE_ADMIN line in your /app/config/core.php file. The
default value of CAKE_ADMIN is 'admin', but you can change it to whatever you like.
Remember this string, because you'll need to prepend it to your administrative actions in your
controller. So, admin actions in this case would be named admin_actionName(). Here's some
examples of desired URLs and possible CAKE_ADMIN and controller action settings:
Plain Text View

/admin/products/add CAKE_ADMIN = 'admin'


name of action in ProductsController =
'admin_add()'

/superuser/news/post CAKE_ADMIN = 'superuser'


name of action in NewsController =
'superuser_post()'

/admin/posts/delete CAKE_ADMIN = 'admin'


name of action in PostsController =
'admin_delete()'
1. /admin/products/add CAKE_ADMIN = 'admin'
2. name of action in ProductsController = 'admin_add()'
3. /superuser/news/post CAKE_ADMIN = 'superuser'
4. name of action in NewsController = 'superuser_post()'
5. /admin/posts/delete CAKE_ADMIN = 'admin'
6. name of action in PostsController = 'admin_delete()'
Using admin routes allows you to keep your logic organized while making the routing very easy
to accomplish. When enabled, you can easily determine in the controller whether an admin route
has been accessed by using:
$this->params[CAKE_ADMIN];
or, assuming 'admin' is the value of CAKE_ADMIN,
$this->params['admin'];
Please note that enabling admin routes or using them does not enable any sort of authentication
or security. You'll need implement those yourself.
Similarly, you can enable Cake's webservices routing to make easier there as well. Have a
controller action you'd like to expose as a webservice? First, set WEBSERVICES in
/app/config/core.php to 'on'. This enables some automatic routing somewhat similar to admin
routing, except that a certain set of route prefixes are enabled:
1. rss
2. xml
3. rest
4. soap
5. xmlrpc
What this does is allows you to provide an alternate views that will automatically be available
at /rss/controllerName/actionName or /soap/controllerName/actionName. This allows you to
create a single action that can have two views: one for normal HTML viewiers, and another for
webservices users. By doing this, you can easily allow much of the functionality of your
application to be available via webservices.
For example, let's say I have some logic in my application that tells users who is on the phone in
my office. I already have a HTML view for this data, but I want to offer it in XML so it can be
used in a desktop widget or handheld application. First I need to enable Cake's webservice
routing:
/app/config/core.php (partial)
Plain Text View

/**
* The define below is used to turn cake built webservices
* on or off. Default setting is off.
*/
define('WEBSERVICES', 'on');
1. /**
2. * The define below is used to turn cake built webservices
3. * on or off. Default setting is off.
4. */
5. define('WEBSERVICES', 'on');
Next, we need to define a component for the type of webservice you want to handle. For XML,
you'd need to include an XmlComponent, with RSS, and RssComponent. Components are
defined in /app/controllers/components, and extend the Object class.
Once that's done, I can structure the logic in my controller just as I normally would:
messages_controller.php
Plain Text View

<?php
class PhonesController extends AppController
{
function doWhosOnline()
{
// this action is where we do all the work of seeing who's on the
phone...

// If I wanted this action to be available via Cake's xml webservices


route,
// I'd need to include a view at
/app/views/phones/xml/do_whos_online.thtml.
// Note: the default view used here is at
/app/views/layouts/xml/default.thtml.

// If a user requests /phones/doWhosOnline, they will get an HTML


version.
// If a user requests /xml/phones/doWhosOnline, they will get the XML
version.
}
}
?>
1. <?php
2. class PhonesController extends AppController
3. {
4. function doWhosOnline()
5. {
6. // this action is where we do all the work of seeing who's on the
phone...
7. // If I wanted this action to be available via Cake's xml webservices
route,
8. // I'd need to include a view at
/app/views/phones/xml/do_whos_online.thtml.
9. // Note: the default view used here is at
/app/views/layouts/xml/default.thtml.
10. // If a user requests /phones/doWhosOnline, they will get an HTML
version.
11. // If a user requests /xml/phones/doWhosOnline, they will get the XML
version.
12. }
13. }
14. ?>
(Optional) Custom Inflections Configuration
Cake's naming conventions can be really nice - you can name your model Box, your controller
Boxes, and everything just works out. There are occasions (especially for our non-english
speaking friends) where you may run into situations where Cake's inflector (the class that
pluralizes, singularizes, camelCases, and under_scores) might not work as you'd like. If Cake
won't recognize your Foci or Fish, editing the custom inflections configuration file is where
you'll need to go.
Found at /app/config/inflections.php is a list of Cake variables you can use to adjust the
pluralization, singularization of classnames in Cake, along with definining terms that shouldn't
be inflected at all (like Fish and Deer, for you outdoorsman cakers) along with irregularities.
Follow the notes inside the file to make adjustments, or use the examples in the file by
uncommenting them. You may need to know a little regex before diving in.

6 Scaffolding
• Edit
• Comments (1)
• History
Cake's Scaffolding is Pretty Cool
So cool that you'll want to use it in production apps. Now, we think its cool, too, but please
realize that scaffolding is... well... just scaffolding. It's a bunch of stuff you throw up real quick
during the beginning of a project in order to get started. It isn't meant to be completely flexible.
So, if you find yourself really wanting to customize your logic and your views, its time to pull
your scaffolding down in order to write some code.
Scaffolding is a great way of getting the early parts of developing a web application started.
Early database schemas are volatile and subject to change, which is perfectly normal in the early
part of the design process. This has a downside: a web developer hates creating forms that never
will see real use. To reduce the strain on the developer, scaffolding has been included in Cake.
Scaffolding analyzes your database tables and creates standard lists with add, delete and edit
buttons, standard forms for editing and standard views for inspecting a single item in the
database. To add scaffolding to your application, in the controller, add the $scaffold variable:
Plain Text View

<?php
class CategoriesController extends AppController
{
var $scaffold;
}
?>
1. <?php
2. class CategoriesController extends AppController
3. {
4. var $scaffold;
5. }
6. ?>
One important thing to note about scaffold: it expects that any field name that ends with _id is a
foreign key to a table which has a name that precedes the underscore. So, for example, if you
have nested categories, you'd probably have a column called category_id in your categories
table.
Also, when you have a foreign key in a table (e.g. titles table has category_id), and you have
associated your models appropriately (see Understanding Associations, 6.2), a select box will be
automatically populated with the rows from the foreign table (titles) in the show/edit/new views.
To set which field in the foreign table is shown, set the $displayField variable in the foreign
model. To continue our example of a category having a title:
Plain Text View

<?php
class Category extends AppModel
{
var $name = 'Category';

var $displayField = 'title';


}
?>
1. <?php
2. class Category extends AppModel
3. {
4. var $name = 'Category';
5. var $displayField = 'title';
6. }
7. ?>
Customizing Scaffold Views
If you're looking for something a little different in your scaffolded views, you can create them
yourself. We still don't recommend using this technique for production applications, but such a
customization may be extremely useful for prototyping iterations.
If you'd like to change your scaffolding views, you'll need to supply your own:
Custom Scaffolding Views for a Single Controller
Custom scaffolding views for a PostsController should be placed like so:
Plain Text View

/app/views/posts/scaffold/scaffold.index.thtml
/app/views/posts/scaffold/scaffold.show.thtml
/app/views/posts/scaffold/scaffold.edit.thtml
/app/views/posts/scaffold/scaffold.new.thtml
1. /app/views/posts/scaffold/scaffold.index.thtml
2. /app/views/posts/scaffold/scaffold.show.thtml
3. /app/views/posts/scaffold/scaffold.edit.thtml
4. /app/views/posts/scaffold/scaffold.new.thtml
Custom Scaffolding Views for an Entire Application
Custom scaffolding views for all controllers should be placed like so:
Plain Text View

/app/views/scaffold/scaffold.index.thtml
/app/views/scaffold/scaffold.show.thtml
/app/views/scaffold/scaffold.edit.thtml
/app/views/scaffold/scaffold.new.thtml
1. /app/views/scaffold/scaffold.index.thtml
2. /app/views/scaffold/scaffold.show.thtml
3. /app/views/scaffold/scaffold.edit.thtml
4. /app/views/scaffold/scaffold.new.thtml
If you find yourself wanting to change the controller logic at this point, it's time to take the
scaffolding down from your application and start building it.
One feature you might find helpful is Cake's code generator: Bake. Bake allows you to generate
a coded version of scaffolded code you can then move on to modify and customize as your
application requires.
« Configuration | Models »

7 Models
• Edit
• Comments (0)
• History

What is a model?
What does it do? It separates domain logic from the presentation, isolating application logic.
A model is generally an access point to the database, and more specifically, to a certain table in
the database. By default, each model uses the table who's name is plural of its own, i.e. a 'User'
model uses the 'users' table. Models can also contain data validation rules, association
information, and methods specific to the table it uses. Here's what a simple User model might
look like in Cake:
Example User Model, saved in /app/models/user.php
Plain Text View

<?php

//AppModel gives you all of Cake's Model functionality

class User extends AppModel


{
// Its always good practice to include this variable.
var $name = 'User';

// This is used for validation, see Chapter "Data Validation".


var $validate = array();

// You can also define associations.


// See section 6.3 for more information.

var $hasMany = array('Image' =>


array('className' => 'Image')
);

// You can also include your own functions:


function makeInactive($uid)
{
//Put your own logic here...
}
}

?>
1. <?php
2. //AppModel gives you all of Cake's Model functionality
3. class User extends AppModel
4. {
5. // Its always good practice to include this variable.
6. var $name = 'User';
7. // This is used for validation, see Chapter "Data Validation".
8. var $validate = array();
9. // You can also define associations.
10. // See section 6.3 for more information.
11. var $hasMany = array('Image' =>
12. array('className' => 'Image')
13. );
14. // You can also include your own functions:
15. function makeInactive($uid)
16. {
17. //Put your own logic here...
18. }
19. }
20. ?>

Model Functions
From a PHP view, models are classes extending the AppModel class. The AppModel class is
originally defined in the cake/ directory, but should you want to create your own, place it in
app/app_model.php. It should contain methods that are shared between two or more models. It
itself extends the Model class which is a standard Cake library defined in cake/libs/model.php.
While this section will treat most of the often-used functions in Cake's Model, it's important to
remember to use http://api.cakephp.org for a full reference.
User-Defined Functions
An example of a table-specific method in the model is a pair of methods for hiding/unhiding
posts in a blog.

Example Model Functions


Plain Text View

<?php
class Post extends AppModel
{
var $name = 'Post';

function hide ($id=null)


{
if ($id)
{
$this->id = $id;
$this->saveField('hidden', '1');
}
}

function unhide ($id=null)


{
if ($id)
{
$this->id = $id;
$this->saveField('hidden', '0');
}
}
}
?>
1. <?php
2. class Post extends AppModel
3. {
4. var $name = 'Post';
5. function hide ($id=null)
6. {
7. if ($id)
8. {
9. $this->id = $id;
10. $this->saveField('hidden', '1');
11. }
12. }
13. function unhide ($id=null)
14. {
15. if ($id)
16. {
17. $this->id = $id;
18. $this->saveField('hidden', '0');
19. }
20. }
21. }
22. ?>
Retrieving Your Data
Below are a few of the standard ways of getting to your data using a model:
• findAll
• string $conditions
• array $fields
• string $order
• int $limit
• int $page
• int $recursive
Returns the specified fields up to $limit records matching $conditions (if any), start listing from
page $page (default is page 1). $conditions should look like they would in an SQL statement:
$conditions = "race = 'wookie' AND thermal_detonators > 3", for example.
When the $recursive option is set to an integer value greater than 1, the findAll() operation will
make an effort to return the models associated to the ones found by the findAll(). If your
property has many owners who in turn have many contracts, a recursive findAll() on your
Property model will return those associated models.
Set $recursive to -1 if you want no associated data fetched during the find.
• find
• string $conditions
• array $fields
• string $order
• int $recursive
Returns the specified (or all if not specified) fields from the first record that matches $conditions.
When the $recursive option is set to an integer value between 1 and 3, the find() operation will
make an effort to return the models associated to the ones found by the find(). The recursive find
can go up to three levels deep. If your property has many owners who in turn have many
contracts, a recursive find() on your Property model will return up to three levels deep of
associated models.
Set $recursive to -1 if you want no associated data fetched durint the find.
• findBy<fieldName>
• string $value
• findAllBy<fieldName>
• string $value
These magic functions can be used as a shortcut to search your tables for a row given a certain
field, and a certain value. Just tack on the name of the field you wish to search, and CamelCase it
(depending on your PHP version). Examples (as used in a Controller) might be:
Plain Text View

//PHP 5 Users
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLastName('Rogers');
$this->Property->findAllByState('AZ');
$this->Specimen->findAllByKingdom('Animalia');
$this->Foo->findAllByThreeWordField('bar');

//PHP 4 Users
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLast_name('Rogers'); //PHP4 isn't as case-friendly
$this->Property->findAllByState('AZ');
$this->Specimen->findAllByKingdom('Animalia');
$this->Foo->findAllByThree_word_field('bar'); //PHP4 isn't as case-friendly
1. //PHP 5 Users
2. $this->Post->findByTitle('My First Blog Post');
3. $this->Author->findByLastName('Rogers');
4. $this->Property->findAllByState('AZ');
5. $this->Specimen->findAllByKingdom('Animalia');
6. $this->Foo->findAllByThreeWordField('bar');
7. //PHP 4 Users
8. $this->Post->findByTitle('My First Blog Post');
9. $this->Author->findByLast_name('Rogers'); //PHP4 isn't as case-friendly
10. $this->Property->findAllByState('AZ');
11. $this->Specimen->findAllByKingdom('Animalia');
12. $this->Foo->findAllByThree_word_field('bar'); //PHP4 isn't as case-
friendly
The returned result is an array formatted just as would be from find() or findAll().
• findNeighbours
• string $conditions
• array $field
• string $value
Returns an array with the neighboring models (with only the specified fields), specified by $field
and $value, filtered by the SQL conditions, $conditions.
This is useful in situations where you want 'Previous' and 'Next' links that walk users through
some ordered sequence through your model entries. It only works for numeric and date based
fields.
Plain Text View

class ImagesController extends AppController


{
function view($id)
{
// Say we want to show the image...

$this->set('image', $this->Image->find("id = $id"));

// But we also want the previous and next images...

$this->set('neighbours', $this->Image->findNeighbours(null, 'id',


$id));

}
}
1. class ImagesController extends AppController
2. {
3. function view($id)
4. {
5. // Say we want to show the image...
6. $this->set('image', $this->Image->find("id = $id"));
7. // But we also want the previous and next images...
8. $this->set('neighbours', $this->Image->findNeighbours(null, 'id', $id));
9. }
10. }
This gives us the full $image['Image'] array, along with $neighbours['prev']['Image']['id'] and
$neighbours['next']['Image']['id'] in our view.
• field
• string $name
• string $conditions
• string $order
Returns as a string a single field from the first record matched by $conditions as ordered by
$order.
• findCount
• string $conditions
Returns the number of records that match the given conditions.
• generateList
• string $conditions
• string $order
• int $limit
• string $keyPath
• string $valuePath
This function is a shortcut to getting a list of key value pairs - especially handy for creating a
html select tag from a list of your models. Use the $conditions, $order, and $limit parameters just
as you would for a findAll() request. The $keyPath and $valuePath are where you tell the model
where to find the keys and values for your generated list. For example, if you wanted to generate
a list of roles based on your Role model, keyed by their integer ids, the full call might look
something like:
Plain Text View

$this->set(
'Roles',
$this->Role->generateList(null, 'role_name ASC', null, '{n}.Role.id',
'{n}.Role.role_name')
);

//This would return something like:


array(
'1' => 'Account Manager',
'2' => 'Account Viewer',
'3' => 'System Manager',
'4' => 'Site Visitor'
);
1. $this->set(
2. 'Roles',
3. $this->Role->generateList(null, 'role_name ASC', null, '{n}.Role.id',
'{n}.Role.role_name')
4. );
5. //This would return something like:
6. array(
7. '1' => 'Account Manager',
8. '2' => 'Account Viewer',
9. '3' => 'System Manager',
10. '4' => 'Site Visitor'
11. );
• read
• string $fields
• string $id
Use this function to get the fields and their values from the currently loaded record, or the record
specified by $id.
The recursiveness of the result depends on the value of $recursive in the model.
• query
• string $query
• execute
• string $query
Custom SQL calls can be made using the model's query() and execute() methods. The difference
between the two is that query() is used to make custom SQL queries (the results of which are
returned), and execute() is used to make custom SQL commands (which require no return value).
Custom Sql Calls with query()
Plain Text View

<?php
class Post extends AppModel
{
var $name = 'Post';

function posterFirstName()
{
$ret = $this->query("SELECT first_name FROM posters_table
WHERE poster_id = 1");
$firstName = $ret[0]['first_name'];
return $firstName;
}
}
?>
1. <?php
2. class Post extends AppModel
3. {
4. var $name = 'Post';
5. function posterFirstName()
6. {
7. $ret = $this->query("SELECT first_name FROM posters_table
8. WHERE poster_id = 1");
9. $firstName = $ret[0]['first_name'];
10. return $firstName;
11. }
12. }
13. ?>
Complex Find Conditions (using arrays)
Most of the model's finder calls involve passing sets of conditions in one way or another. The
simplest approach to this is to use a WHERE clause snippet of SQL, but if you need more
control, you can use arrays. Using arrays is clearer and easier to read, and also makes it very easy
to build queries. This syntax also breaks out the elements of your query (fields, values, operators,
etc.) into discrete, manipulatable parts. This allows Cake to generate the most efficient query
possible, ensure proper SQL syntax, and properly escape each individual part of the query.
At it's most basic, an array-based query looks like this:
Basic find conditions array usage example:
Plain Text View

$conditions = array("Post.title" => "This is a post");

//Example usage with a model:


$this->Post->find($conditions);
1. $conditions = array("Post.title" => "This is a post");
2. //Example usage with a model:
3. $this->Post->find($conditions);
The structure is fairly self-explanatory: it will find any post where the title matches the string
"This is a post". Note that we could have used just "title" as the field name, but when building
queries, it is good practice to always specify the model name, as it improves the clarity of the
code, and helps prevent collisions in the future, should you choose to change your schema. What
about other types of matches? These are equally simple. Let's say we wanted to find all the posts
where the title is not "This is a post":
Plain Text View

array("Post.title" => "<> This is a post")


1. array("Post.title" => "<> This is a post")
All that was added was '<>' before the expression. Cake can parse out any valid SQL comparison
operator, including match expressions using LIKE, BETWEEN, or REGEX, as long as you leave
a space between the operator an the expression or value. The one exception here is IN (...)-style
matches. Let's say you wanted to find posts where the title was in a given set of values:
Plain Text View

array("Post.title" => array("First post", "Second post", "Third post"))


1. array("Post.title" => array("First post", "Second post", "Third post"))
Adding additional filters to the conditions is as simple as adding additional key/value pairs to the
array:
Plain Text View

array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
1. array
2. (
3. "Post.title" => array("First post", "Second post", "Third post"),
4. "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
5. )
By default, Cake joins multiple conditions with boolean AND; which means, the snippet above
would only match posts that have been created in the past two weeks, and have a title that
matches one in the given set. However, we could just as easily find posts that match either
condition:
Plain Text View

array
("or" =>
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
)
1. array
2. ("or" =>
3. array
4. (
5. "Post.title" => array("First post", "Second post", "Third post"),
6. "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
7. )
8. )
Cake accepts all valid SQL boolean operations, including AND, OR, NOT, XOR, etc., and they
can be upper or lower case, whichever you prefer. These conditions are also infinitely nestable.
Let's say you had a hasMany/belongsTo relationship between Posts and Authors, which would
result in a LEFT JOIN on the find done on Post. Let's say you wanted to find all the posts that
contained a certain keyword or were created in the past two weeks, but you want to restrict your
search to posts written by Bob:
Plain Text View
array
("Author.name" => "Bob", "or" => array
(
"Post.title" => "LIKE %magic%",
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")
)
)
1. array
2. ("Author.name" => "Bob", "or" => array
3. (
4. "Post.title" => "LIKE %magic%",
5. "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")
6. )
7. )
Saving Your Data
To save data to your model, you need to supply it with the data you wish to save. The data
handed to the save() method should be in the following form:
Plain Text View

Array
(
[ModelName] => Array
(
[fieldname1] => 'value'
[fieldname2] => 'value'
)
)
1. Array
2. (
3. [ModelName] => Array
4. (
5. [fieldname1] => 'value'
6. [fieldname2] => 'value'
7. )
8. )
In order to get your data posted to the controller in this manner, it's easiest just to use the HTML
Helper to do this, because it creates form elements that are named in the way Cake expects. You
don't need to use it however: just make sure your form elements have names that look like
data[Modelname][fieldname]. Using $html->input('Model/fieldname') is the easiest, however.
Data posted from forms is automatically formatted like this and placed in $this->data inside of
your controller, so saving your data from web forms is a snap. An edit function for a property
controller might look something like the following:
Plain Text View
function edit($id)
{

//Note: The property model is automatically loaded for us at $this-


>Property.

// Check to see if we have form data...


if (empty($this->data))
{
$this->Property->id = $id;
$this->data = $this->Property->read();//populate the form fields with
the current row
}
else
{
// Here's where we try to save our data. Automagic validation checking
if ($this->Property->save($this->data['Property']))
{
//Flash a message and redirect.
$this->flash('Your information has been saved.',
'/properties/view/'.$this->data['Property']['id'], 2);
}
//if some fields are invalid or save fails the form will render
}
}
1. function edit($id)
2. {
3. //Note: The property model is automatically loaded for us at $this-
>Property.
4. // Check to see if we have form data...
5. if (empty($this->data))
6. {
7. $this->Property->id = $id;
8. $this->data = $this->Property->read();//populate the form fields with
the current row
9. }
10. else
11. {
12. // Here's where we try to save our data. Automagic validation checking
13. if ($this->Property->save($this->data['Property']))
14. {
15. //Flash a message and redirect.
16. $this->flash('Your information has been saved.',
17. '/properties/view/'.$this->data['Property']['id'], 2);
18. }
19. //if some fields are invalid or save fails the form will render
20. }
21. }
Notice how the save operation is placed inside a conditional: when you try to save data to your
model, Cake automatically attempts to validate your data using the rules you've provided. To
learn more about data validation, see Chapter "Data Validation". If you do not want save() to try
to validate your data, use save($data, false).
Other useful save functions:
• del
• string $id
• boolean $cascade
Deletes the model specified by $id, or the current id of the model.
If this model is associated to other models, and the 'dependent' key has been set in the association
array, this method will also delete those associated models if $cascade is set to true.
Returns true on success.
• saveField
• string $name
• string $value
Used to save a single field value.
• getLastInsertId
Returns the ID of the most recently created record.
Model Callbacks
We've added some model callbacks that allow you to sneak in logic before or after certain model
operations. To gain this functionality in your applications, use the parameters provided and
override these functions in your Cake models.
• beforeFind
• string $conditions
The beforeFind() callback is executed just before a find operation begins. Place any pre-find
logic in this method. When you override this in your model, return true when you want the find
to execute, and false when you want it to abort.
• afterFind
• array $results
Use this callback to modify results that have been returned from a find operation, or perform any
other post-find logic. The parameter for this function is the returned results from the model's find
operation, and the return value is the modified results.
• beforeValidate
Use this callback to modify model data before it is validated. It can also be used to add
additional, more complex validation rules, using Model::invalidate(). In this context, model
data is accessible via $this->data. This function must also return true, otherwise save()
execution will abort.
• beforeSave
Place any pre-save logic in this function. This function executes immediately after model data
has been validated (assuming it validates, otherwise the save() call aborts, and this callback will
not execute), but before the data is saved. This function should also return true if you want the
save operation to continue, and false if you want to abort.
One usage of beforeSave might be to format time data for storage in a specifc database engine:
Plain Text View

// Date/time fields created by HTML Helper:


// This code would be seen in a view

$html->dayOptionTag('Event/start');
$html->monthOptionTag('Event/start');
$html->yearOptionTag('Event/start');
$html->hourOptionTag('Event/start');
$html->minuteOptionTag('Event/start');

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

// Model callback functions used to stitch date


// data together for storage
// This code would be seen in the Event model:

function beforeSave()
{
$this->data['Event']['start'] = $this->_getDate('Event', 'start');

return true;
}

function _getDate($model, $field)


{
return date('Y-m-d H:i:s', mktime(
intval($this->data[$model][$field . '_hour']),
intval($this->data[$model][$field . '_min']),
null,
intval($this->data[$model][$field . '_month']),
intval($this->data[$model][$field . '_day']),
intval($this->data[$model][$field . '_year'])));
}
1. // Date/time fields created by HTML Helper:
2. // This code would be seen in a view
3. $html->dayOptionTag('Event/start');
4. $html->monthOptionTag('Event/start');
5. $html->yearOptionTag('Event/start');
6. $html->hourOptionTag('Event/start');
7. $html->minuteOptionTag('Event/start');
8. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
9. // Model callback functions used to stitch date
10. // data together for storage
11. // This code would be seen in the Event model:
12. function beforeSave()
13. {
14. $this->data['Event']['start'] = $this->_getDate('Event', 'start');
15. return true;
16. }
17. function _getDate($model, $field)
18. {
19. return date('Y-m-d H:i:s', mktime(
20. intval($this->data[$model][$field . '_hour']),
21. intval($this->data[$model][$field . '_min']),
22. null,
23. intval($this->data[$model][$field . '_month']),
24. intval($this->data[$model][$field . '_day']),
25. intval($this->data[$model][$field . '_year'])));
26. }
• afterSave
Place any logic that you want to be executed after every save in this callback method.
• beforeDelete
Place any pre-deletion logic in this function. This function should return true if you want the
deletion to continue, and false if you want to abort.
• afterDelete
Place any logic that you want to be executed after every deletion in this callback method.

Model Variables
When creating your models, there are a number of special variables you can set in order to gain
access to Cake functionality:
$primaryKey
If this model relates to a database table, and the table's primary key is not named 'id', use this
variable to tell Cake the name of the primary key.
$recursive
This sets the number of levels you wish Cake to fetch associated model data in find() and
findAll() operations.
Imagine you have Groups which have many Users which in turn have many Articles.
Model::recursive options
$recursive
No associated data is fetched.
= -1

$recursive
Cake fetches Group data
=0

$recursive
Cake fetches a Group and its associated Users
=1

$recursive Cake fetches a Group, its associated Users, and the Users'
=2 associated Articles

$transactional
Tells Cake whether or not to enable transactions for this model (i.e. begin/commit/rollback). Set
to a boolean value. Only available for supporting databases.
$useTable
If the database table you wish to use isn't the plural form of the model name (and you don't wish
to change the table name), set this variable to the name of the table you'd like this model to use.
$validate
An array used to validate the data passed to this model. See Chapter "Data Validation".
$useDbConfig
Remember the database settings you can configure in /app/config/database.php? Use this
variable to switch between them - just use the name of the database connection variable you've
created in your database configuration file. The default is, you guessed it, 'default'.

Associations
Introduction
One of the most powerful features of CakePHP is the relational mapping provided by the model.
In CakePHP, the links between tables are handled through associations. Associations are the glue
between related logical units.
There are four types of associations in CakePHP:
1. hasOne
2. hasMany
3. belongsTo
4. hasAndBelongsToMany
When associations between models have been defined, Cake will automagically fetch models
related to the model you are working with. For example, if a Post model is related to an Author
model using a hasMany association, making a call to $this->Post->findAll() in a controller will
fetch Post records, as well as all the Author records they are related to.
To use the association correctly it is best to follow the CakePHP naming conventions (see
Appendix "Cake Conventions"). If you use CakePHP's naming conventions, you can use
scaffolding to visualize your application data, because scaffolding detects and uses the
associations between models. Of course you can always customize model associations to work
outside of Cake's naming conventions, but we'll save those tips for later. For now, let's just stick
to the conventions. The naming conventions that concern us here are the foreign keys, model
names, and table names.
Here's a review of what Cake expects for the names of these different elements: (see Appendix
"Cake Conventions" for more information on naming)
• Foreign Keys: [singular model name]_id. For example, a foreign key in the
"authors" table pointing back to the Post a given Author belongs to would be
named "post_id".
• Table Names: [plural object name]. Since we'd like to store information about
blog posts and their authors, the table names are "posts" and "authors",
respectively.
• Model Names: [CamelCased, singular form of table name]. The model name
for the "posts" table is "Post", and the model name for the "authors" table is
"Author".
CakePHP's scaffolding expects your associations to be in the same order as your columns. So if I
have an Article that belongsTo three other models (Author, Editor, and Publisher), I would need
three keys: author_id, editor_id, and publisher_id. Scaffolding would expect your associations in
the same order as the keys in the table (e.g. first Author, second Editor, lastly Publisher).
In order to illustrate how some of these associations work, let's continue using the blog
application as an example. Imagine that we're going to create a simple user management system
for the blog. I suppose it goes without saying we'll want to keep track of Users, but we'd also like
each user to have an associated Profile (User hasOne Profile). Users will also be able to create
comments and remain associated to them (User hasMany Comments). Once we have the user
system working, we'll move to allowing Posts to be related to Tag objects using the
hasAndBelongsToMany relationship (Post hasAndBelongsToMany Tags).
Defining and Querying with hasOne
In order to set up this association, we'll assume that you've already created the User and Profile
models. To define the hasOne assocation between them, we'll need to add an array to the models
to tell Cake how they relate:
/app/models/user.php hasOne
Plain Text View

<?php
class User extends AppModel
{
var $name = 'User';
var $hasOne = array('Profile' =>
array('className' => 'Profile',
'conditions' => '',
'order' => '',
'dependent' => true,
'foreignKey' => 'user_id'
)
);
}
?>
1. <?php
2. class User extends AppModel
3. {
4. var $name = 'User';
5. var $hasOne = array('Profile' =>
6. array('className' => 'Profile',
7. 'conditions' => '',
8. 'order' => '',
9. 'dependent' => true,
10. 'foreignKey' => 'user_id'
11. )
12. );
13. }
14. ?>
The $hasOne array is what Cake uses to build the association between the User and Profile
models. Each key in the array allows you to further configure the association:
1. className (required): the classname of the model you'd like to associate
For our example, we want to specify the 'Profile' model class name.
2. conditions: SQL condition fragments that define the relationship
We could use this to tell Cake to only associate a Profile that has a green header, if we
wished. To define conditions like this, you'd specify a SQL conditions fragment as the
value for this key: "Profile.header_color = 'green'".
3. order: the ordering of the associated models
If you'd like your associated models in a specific order, set the value for this key using an
SQL order predicate: "Profile.name ASC", for example.
4. dependent: if set to true, the associated model is destroyed when this one is.
For example, if the "Cool Blue" profile is associated to "Bob", and I delete the user
"Bob", the profile "Cool Blue" will also be deleted.
5. foreignKey: the name of the foreign key that points to the associated model.
This is here in case you're working with a database that doesn't follow Cake's naming
conventions.
Now, when we execute find() or findAll() calls using the Profile model, we should see our
associated User model there as well:
Plain Text View

$user = $this->User->read(null, '25');


print_r($user);
//output:

Array
(
[User] => Array
(
[id] => 25
[first_name] => John
[last_name] => Anderson
[username] => psychic
[password] => c4k3roxx
)

[Profile] => Array


(
[id] => 4
[name] => Cool Blue
[header_color] => aquamarine
[user_id] = 25
)
)
1. $user = $this->User->read(null, '25');
2. print_r($user);
3. //output:
4. Array
5. (
6. [User] => Array
7. (
8. [id] => 25
9. [first_name] => John
10. [last_name] => Anderson
11. [username] => psychic
12. [password] => c4k3roxx
13. )
14. [Profile] => Array
15. (
16. [id] => 4
17. [name] => Cool Blue
18. [header_color] => aquamarine
19. [user_id] = 25
20. )
21. )
Defining and Querying with belongsTo
Now that a User can see its Profile, we'll need to define an association so Profile can see its User.
This is done in Cake using the belongsTo assocation. In the Profile model, we'd do the
following:
/app/models/profile.php belongsTo
Plain Text View

<?php
class Profile extends AppModel
{
var $name = 'Profile';
var $belongsTo = array('User' =>
array('className' => 'User',
'conditions' => '',
'order' => '',
'foreignKey' => 'user_id'
)
);
}
?>
1. <?php
2. class Profile extends AppModel
3. {
4. var $name = 'Profile';
5. var $belongsTo = array('User' =>
6. array('className' => 'User',
7. 'conditions' => '',
8. 'order' => '',
9. 'foreignKey' => 'user_id'
10. )
11. );
12. }
13. ?>
The $belongsTo array is what Cake uses to build the association between the User and Profile
models. Each key in the array allows you to further configure the association:
1. className (required): the classname of the model you'd like to associate
For our example, we want to specify the 'User' model class name.
2. conditions: SQL condition fragments that define the relationship
We could use this to tell Cake to only associate a User that is active. You would do this
by setting the value of the key to be "User.active = '1'", or something similar.
3. order: the ordering of the associated models
If you'd like your associated models in a specific order, set the value for this key using an
SQL order predicate: "User.last_name ASC", for example.
4. foreignKey: the name of the foreign key that points to the associated model.
This is here in case you're working with a database that doesn't follow Cake's naming
conventions.
Now, when we execute find() or findAll() calls using the Profile model, we should see our
associated User model there as well:
Plain Text View

$profile = $this->Profile->read(null, '4');


print_r($profile);

//output:

Array
(

[Profile] => Array


(
[id] => 4
[name] => Cool Blue
[header_color] => aquamarine
[user_id] = 25
)

[User] => Array


(
[id] => 25
[first_name] => John
[last_name] => Anderson
[username] => psychic
[password] => c4k3roxx
)
)
1. $profile = $this->Profile->read(null, '4');
2. print_r($profile);
3. //output:
4. Array
5. (
6. [Profile] => Array
7. (
8. [id] => 4
9. [name] => Cool Blue
10. [header_color] => aquamarine
11. [user_id] = 25
12. )
13. [User] => Array
14. (
15. [id] => 25
16. [first_name] => John
17. [last_name] => Anderson
18. [username] => psychic
19. [password] => c4k3roxx
20. )
21. )
Defining and Querying with hasMany
Now that User and Profile models are associated and working properly, let's build our system so
that User records are associated to Comment records. This is done in the User model like so:
/app/models/user.php hasMany
Plain Text View

<?php
class User extends AppModel
{
var $name = 'User';
var $hasMany = array('Comment' =>
array('className' => 'Comment',
'conditions' => 'Comment.moderated = 1',
'order' => 'Comment.created DESC',
'limit' => '5',
'foreignKey' => 'user_id',
'dependent' => true,
'exclusive' => false,
'finderQuery' => '',
'fields' => '',
'offset' => '',
'counterQuery' => ''
)
);

// Here's the hasOne relationship we defined earlier...


var $hasOne = array('Profile' =>
array('className' => 'Profile',
'conditions' => '',
'order' => '',
'dependent' => true,
'foreignKey' => 'user_id'
)
);
}
?>
1. <?php
2. class User extends AppModel
3. {
4. var $name = 'User';
5. var $hasMany = array('Comment' =>
6. array('className' => 'Comment',
7. 'conditions' => 'Comment.moderated = 1',
8. 'order' => 'Comment.created DESC',
9. 'limit' => '5',
10. 'foreignKey' => 'user_id',
11. 'dependent' => true,
12. 'exclusive' => false,
13. 'finderQuery' => '',
14. 'fields' => '',
15. 'offset' => '',
16. 'counterQuery' => ''
17. )
18. );
19. // Here's the hasOne relationship we defined earlier...
20. var $hasOne = array('Profile' =>
21. array('className' => 'Profile',
22. 'conditions' => '',
23. 'order' => '',
24. 'dependent' => true,
25. 'foreignKey' => 'user_id'
26. )
27. );
28. }
29. ?>
The $hasMany array is what Cake uses to build the association between the User and Comment
models. Each key in the array allows you to further configure the association:
1. className (required): the classname of the model you'd like to associate
For our example, we want to specify the 'Comment' model class name.
2. conditions: SQL condition fragments that define the relationship
We could use this to tell Cake to only associate a Comment that has been moderated. You
would do this by setting the value of the key to be "Comment.moderated = 1", or
something similar.
3. order: the ordering of the associated models
If you'd like your associated models in a specific order, set the value for this key using an
SQL order predicate: "Comment.created DESC", for example.
4. limit: the maximum number of associated models you'd like Cake to fetch.
For this example, we didn't want to fetch *all* of the user's comments, just five.
5. foreignKey: the name of the foreign key that points to the associated model.
This is here in case you're working with a database that doesn't follow Cake's naming
conventions.
6. dependent: if set to true, the associated models are destroyed when this one is.
For example, if the "Cool Blue" and "Hot Red" profiles are associated to "Bob", and I
delete the user "Bob", the profiles "Cool Blue" and "Hot Red" will also be deleted.
7. exclusive: If set to true, all the associated objects are deleted in one SQL statement
without having their beforeDelete callback run.
Good for use for simpler associations, because it can be much faster.
8. finderQuery: Specify a complete SQL statement to fetch the association.
This is a good way to go for complex associations that depends on multiple tables. If
Cake's automatic assocations aren't working for you, here's where you customize it.
9. fields: Specify the fields from the associated model you wish to fetch.
This is useful for associations where not all the fields are needed with every find() call.
Limiting the amount of fields you request can increase database performance.
10. offset: The number of records to skip before associating to the current model.
11. counterQuery: Specify a complete SQL statement used to count the number of records
that should be associated.
Now, when we execute find() or findAll() calls using the User model, we should see our
associated Comment models there as well:
Plain Text View

$user = $this->User->read(null, '25');


print_r($user);

//output:

Array
(
[User] => Array
(
[id] => 25
[first_name] => John
[last_name] => Anderson
[username] => psychic
[password] => c4k3roxx
)

[Profile] => Array


(
[id] => 4
[name] => Cool Blue
[header_color] => aquamarine
[user_id] = 25
)

[Comment] => Array


(
[0] => Array
(
[id] => 247
[user_id] => 25
[body] => The hasMany assocation is nice to have.
)

[1] => Array


(
[id] => 256
[user_id] => 25
[body] => The hasMany assocation is really nice to have.
)

[2] => Array


(
[id] => 269
[user_id] => 25
[body] => The hasMany assocation is really, really nice
to have.
)

[3] => Array


(
[id] => 285
[user_id] => 25
[body] => The hasMany assocation is extremely nice to
have.
)

[4] => Array


(
[id] => 286
[user_id] => 25
[body] => The hasMany assocation is super nice to have.
)

)
)
1. $user = $this->User->read(null, '25');
2. print_r($user);
3. //output:
4. Array
5. (
6. [User] => Array
7. (
8. [id] => 25
9. [first_name] => John
10. [last_name] => Anderson
11. [username] => psychic
12. [password] => c4k3roxx
13. )
14. [Profile] => Array
15. (
16. [id] => 4
17. [name] => Cool Blue
18. [header_color] => aquamarine
19. [user_id] = 25
20. )
21. [Comment] => Array
22. (
23. [0] => Array
24. (
25. [id] => 247
26. [user_id] => 25
27. [body] => The hasMany assocation is nice to have.
28. )
29. [1] => Array
30. (
31. [id] => 256
32. [user_id] => 25
33. [body] => The hasMany assocation is really nice to have.
34. )
35. [2] => Array
36. (
37. [id] => 269
38. [user_id] => 25
39. [body] => The hasMany assocation is really, really nice to have.
40. )
41. [3] => Array
42. (
43. [id] => 285
44. [user_id] => 25
45. [body] => The hasMany assocation is extremely nice to have.
46. )
47. [4] => Array
48. (
49. [id] => 286
50. [user_id] => 25
51. [body] => The hasMany assocation is super nice to have.
52. )
53. )
54. )
While we won't document the process here, it would be a great idea to define the "Comment
belongsTo User" association as well, so that both models can see each other. Not defining
assocations from both models is often a common gotcha when trying to use scaffolding.
Defining and Querying with hasAndBelongsToMany
Now that you've mastered the simpler associations, let's move to the last assocation:
hasAndBelongsToMany (or HABTM). This last one is the hardest to wrap your head around, but
it is also one of the most useful. The HABTM association is useful when you have two Models
that are linked together with a join table. The join table holds the individual rows that are related
to each other.
The difference between hasMany and hasAndBelongsToMany is that with hasMany, the
associated model is not shared. If a User hasMany Comments, it is the *only* user associated to
those comments. With HABTM, the associated models are shared. This is great for what we're
about to do next: associate Post models to Tag models. When a Tag belongs to a Post, we don't
want it to be 'used up', we want to continue to associate it to other Posts as well.
In order to do this, we'll need to set up the correct tables for this association. Of course you'll
need a "tags" table for you Tag model, and a "posts" table for your posts, but you'll also need to
create a join table for this association. The naming convention for HABTM join tables is [plural
model name1]_[plural model name2], where the model names are in alphabetical order:
HABTM Join Tables: Sample models and their join table names
1. Posts and Tags: posts_tags
2. Monkeys and IceCubes: ice_cubes_monkeys
3. Categories and Articles: articles_categories
HABTM join tables need to at least consist of the two foreign keys of the models they link. For
our example, "post_id" and "tag_id" is all we'll need.
Here's what the SQL dumps will look like for our Posts HABTM Tags example:
Plain Text View

--
-- Table structure for table `posts`
--

CREATE TABLE `posts` (


`id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) default NULL,
`title` varchar(50) default NULL,
`body` text,
`created` datetime default NULL,
`modified` datetime default NULL,
`status` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;

-- --------------------------------------------------------

--
-- Table structure for table `posts_tags`
--

CREATE TABLE `posts_tags` (


`post_id` int(10) unsigned NOT NULL default '0',
`tag_id` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`post_id`,`tag_id`)
) TYPE=MyISAM;

-- --------------------------------------------------------

--
-- Table structure for table `tags`
--

CREATE TABLE `tags` (


`id` int(10) unsigned NOT NULL auto_increment,
`tag` varchar(100) default NULL,
PRIMARY KEY (`id`)
) TYPE=MyISAM;
1. --
2. -- Table structure for table `posts`
3. --
4. CREATE TABLE `posts` (
5. `id` int(10) unsigned NOT NULL auto_increment,
6. `user_id` int(10) default NULL,
7. `title` varchar(50) default NULL,
8. `body` text,
9. `created` datetime default NULL,
10. `modified` datetime default NULL,
11. `status` tinyint(1) NOT NULL default '0',
12. PRIMARY KEY (`id`)
13. ) TYPE=MyISAM;
14. -- --------------------------------------------------------
15. --
16. -- Table structure for table `posts_tags`
17. --
18. CREATE TABLE `posts_tags` (
19. `post_id` int(10) unsigned NOT NULL default '0',
20. `tag_id` int(10) unsigned NOT NULL default '0',
21. PRIMARY KEY (`post_id`,`tag_id`)
22. ) TYPE=MyISAM;
23. -- --------------------------------------------------------
24. --
25. -- Table structure for table `tags`
26. --
27. CREATE TABLE `tags` (
28. `id` int(10) unsigned NOT NULL auto_increment,
29. `tag` varchar(100) default NULL,
30. PRIMARY KEY (`id`)
31. ) TYPE=MyISAM;
With our tables set up, let's define the association in the Post model:
/app/models/post.php hasAndBelongsToMany
Plain Text View

<?php
class Post extends AppModel
{
var $name = 'Post';
var $hasAndBelongsToMany = array('Tag' =>
array('className' => 'Tag',
'joinTable' => 'posts_tags',
'foreignKey' => 'post_id',
'associationForeignKey'=> 'tag_id',
'conditions' => '',
'order' => '',
'limit' => '',
'unique' => true,
'finderQuery' => '',
'deleteQuery' => '',
)
);
}
?>
1. <?php
2. class Post extends AppModel
3. {
4. var $name = 'Post';
5. var $hasAndBelongsToMany = array('Tag' =>
6. array('className' => 'Tag',
7. 'joinTable' => 'posts_tags',
8. 'foreignKey' => 'post_id',
9. 'associationForeignKey'=> 'tag_id',
10. 'conditions' => '',
11. 'order' => '',
12. 'limit' => '',
13. 'unique' => true,
14. 'finderQuery' => '',
15. 'deleteQuery' => '',
16. )
17. );
18. }
19. ?>
The $hasAndBelongsToMany array is what Cake uses to build the association between the Post
and Tag models. Each key in the array allows you to further configure the association:
1. className (required): the classname of the model you'd like to associate
For our example, we want to specify the 'Tag' model class name.
2. joinTable: this is here for a database that doesn't adhere to Cake's naming conventions. If
your table doesn't look like [plural model1]_[plural model2] in lexical order, you can
specify the name of your table here.
3. foreignKey: the name of the foreign key in the join table that points to the current model.
This is here in case you're working with a database that doesn't follow Cake's naming
conventions.
4. associationForeignKey: the name of the foreign key that points to the associated model.
5. conditions: SQL condition fragments that define the relationship
We could use this to tell Cake to only associate a Tag that has been approved. You would
do this by setting the value of the key to be "Tag.approved = 1", or something similar.
6. order: the ordering of the associated models
If you'd like your associated models in a specific order, set the value for this key using an
SQL order predicate: "Tag.tag DESC", for example.
7. limit: the maximum number of associated models you'd like Cake to fetch.
Used to limit the number of associated Tags to be fetched.
8. unique: If set to true, duplicate associated objects will be ignored by accessors and query
methods.
Basically, if the associations are distinct, set this to true. That way the Tag
"Awesomeness" can only be assigned to the Post "Cake Model Associations" once, and
will only show up once in result arrays.
9. finderQuery: Specify a complete SQL statement to fetch the association.
This is a good way to go for complex associations that depends on multiple tables. If
Cake's automatic assocations aren't working for you, here's where you customize it.
10. deleteQuery: A complete SQL statement to be used to remove assocations between
HABTM models.
If you don't like the way Cake is performing deletes, or your setup is customized in some
way, you can change the way deletion works by supplying your own query here.
Now, when we execute find() or findAll() calls using the Post model, we should see our
associated Tag models there as well:
Plain Text View

$post = $this->Post->read(null, '2');


print_r($post);

//output:

Array
(
[Post] => Array
(
[id] => 2
[user_id] => 25
[title] => Cake Model Associations
[body] => Time saving, easy, and powerful.
[created] => 2006-04-15 09:33:24
[modified] => 2006-04-15 09:33:24
[status] => 1
)

[Tag] => Array


(
[0] => Array
(
[id] => 247
[tag] => CakePHP
)

[1] => Array


(
[id] => 256
[tag] => Powerful Software
)
)
)
1. $post = $this->Post->read(null, '2');
2. print_r($post);
3. //output:
4. Array
5. (
6. [Post] => Array
7. (
8. [id] => 2
9. [user_id] => 25
10. [title] => Cake Model Associations
11. [body] => Time saving, easy, and powerful.
12. [created] => 2006-04-15 09:33:24
13. [modified] => 2006-04-15 09:33:24
14. [status] => 1
15. )
16. [Tag] => Array
17. (
18. [0] => Array
19. (
20. [id] => 247
21. [tag] => CakePHP
22. )
23. [1] => Array
24. (
25. [id] => 256
26. [tag] => Powerful Software
27. )
28. )
29. )
Saving Related Model Data
One important thing to remember when working with associated models is that saving model
data should always be done by the corresponding Cake model. If you are saving a new Post and
its associated Comments, then you would use both Post and Comment models during the save
operation.
If neither of the associated models exists in the system yet (for example, you want to save a new
Post and a related Comment at the same time), you'll need to first save the primary, or parent
model. To get an idea of how this works, let's imagine that we have an action in our
PostsController that handles the saving of a new Post and a related Comment. The example
action shown below will assume that you've posted a single Post and a single Comment.
/app/controllers/posts_controller.php (partial)
Plain Text View

function add()
{
if (!empty($this->data))
{
//We can save the Post data:
//it should be in $this->data['Post']

$this->Post->save($this->data);

//Now, we'll need to save the Comment data


//But first, we need to know the ID for the
//Post we just saved...

$post_id = $this->Post->getLastInsertId();

//Now we add this information to the save data


//and save the comment.

$this->data['Comment']['post_id'] = $post_id;

//Because our Post hasMany Comments, we can access


//the Comment model through the Post model:

$this->Post->Comment->save($this->data);

}
}
1. function add()
2. {
3. if (!empty($this->data))
4. {
5. //We can save the Post data:
6. //it should be in $this->data['Post']
7.
8. $this->Post->save($this->data);
9. //Now, we'll need to save the Comment data
10. //But first, we need to know the ID for the
11. //Post we just saved...
12. $post_id = $this->Post->getLastInsertId();
13. //Now we add this information to the save data
14. //and save the comment.
15. $this->data['Comment']['post_id'] = $post_id;
16. //Because our Post hasMany Comments, we can access
17. //the Comment model through the Post model:
18. $this->Post->Comment->save($this->data);
19. }
20. }
If, however, the parent model already exists in the system (for example, adding a Comment to an
existing Post), you need to know the ID of the parent model before saving. You could pass this
ID as a URL parameter, or as a hidden element in a form...
/app/controllers/posts_controller.php (partial)
Plain Text View

//Here's how it would look if the URL param is used...


function addComment($post_id)
{
if (!empty($this->data))
{
//You might want to make the $post_id data more safe,
//but this will suffice for a working example..

$this->data['Comment']['post_id'] = $post_id;

//Because our Post hasMany Comments, we can access


//the Comment model through the Post model:

$this->Post->Comment->save($this->data);
}
}
1. //Here's how it would look if the URL param is used...
2. function addComment($post_id)
3. {
4. if (!empty($this->data))
5. {
6. //You might want to make the $post_id data more safe,
7. //but this will suffice for a working example..
8. $this->data['Comment']['post_id'] = $post_id;
9. //Because our Post hasMany Comments, we can access
10. //the Comment model through the Post model:
11. $this->Post->Comment->save($this->data);
12. }
13. }
If the ID was passed as a hidden element in the form, you might want to name the field (if you're
using the HtmlHelper) so it ends up in the posted data where it needs to be:
If the ID for the post is at $post['Post']['id']...

Plain Text View

<?php echo $html->hidden('Comment/post_id', array('value' => $post['Post']


['id'])); ?>
1. <?php echo $html->hidden('Comment/post_id', array('value' =>
$post['Post']['id'])); ?>
Done this way, the ID for the parent Post model can be accessed at $this->data['Comment']
['post_id'], and is all ready for a simple $this->Post->Comment->save($this->data) call.
These same basic techniques will work if you're saving multiple child models, just place those
save() calls in a loop (and remember to clear the model information using Model::create()).
In summary, if you're saving associated data (for belongsTo, hasOne, and hasMany relations),
the main point is getting the ID of the parent model and saving it to the child model.
Saving hasAndBelongsToMany Relations
Saving models that are associated by hasOne, belongsTo, and hasMany is pretty simple: you just
populate the foreign key field with the ID of the associated model. Once that's done, you just call
the save() method on the model, and everything gets linked up correctly.
With hasAndBelongsToMany, its a bit trickier, but we've gone out of our way to make it as
simple as possible. In keeping along with our example, we'll need to make some sort of form that
relates Tags to Posts. Let's now create a form that creates posts, and associates them to an
existing list of Tags.
You might actually like to create a form that creates new tags and associates them on the fly - but
for simplicity's sake, we'll just show you how to associate them and let you take it from there.
When you're saving a model on its own in Cake, the tag name (if you're using the Html Helper)
looks like 'Model/field_name'. Let's just start out with the part of the form that creates our post:
/app/views/posts/add.thtml Form for creating posts
Plain Text View

<h1>Write a new post</h1>


<form method="post" action="<?php echo $html->url('/posts/add'); ?>">
<table>
<tr>
<td>Title:</td>
<td><?php echo $html->input('Post/title')?></td>
</tr>
<tr>
<td>Body:<td>
<td><?php echo $html->textarea('Post/body')?></td>
</tr>
<tr>
<td colspan="2">
<?php echo $html->hidden('Post/user_id', array('value' =>
$session->read('User.id')))?>
<?php echo $html->hidden('Post/status' , array('value' => '0'))?>
<?php echo $html->submit('Save Post')?>
</td>
</tr>
</table>
</form>
1. <h1>Write a new post</h1>
2. <form method="post" action="<?php echo $html->url('/posts/add'); ?>">
3. <table>
4. <tr>
5. <td>Title:</td>
6. <td><?php echo $html->input('Post/title')?></td>
7. </tr>
8. <tr>
9. <td>Body:<td>
10. <td><?php echo $html->textarea('Post/body')?></td>
11. </tr>
12. <tr>
13. <td colspan="2">
14. <?php echo $html->hidden('Post/user_id', array('value' => $session-
>read('User.id')))?>
15. <?php echo $html->hidden('Post/status' , array('value' => '0'))?>
16. <?php echo $html->submit('Save Post')?>
17. </td>
18. </tr>
19. </table>
20. </form>
The form as it stands now will just create Post records. Let's add some code to allow us to bind a
given Post to one or many Tags:
/app/views/posts/add.thtml (Tag association code added)
Plain Text View

<h1>Write a new post</h1>


<form method="post" action="<?php echo $html->url('/posts/add'); ?>">
<table>
<tr>
<td>Title:</td>
<td><?php echo $html->input('Post/title')?></td>
</tr>
<tr>
<td>Body:</td>
<td><?php echo $html->textarea('Post/body')?></td>
</tr>
<tr>
<td>Related Tags:</td>
<td><?php echo $html->selectTag('Tag/Tag', $tags, null,
array('multiple' => 'multiple')) ?>
</td>
</tr>
<tr>
<td colspan="2">
<?php echo $html->hidden('Post/user_id', array('value' =>
$session->read('User.id')))?>
<?php echo $html->hidden('Post/status' , array('value' => '0'))?>
<?php echo $html->submit('Save Post')?>
</td>
</tr>
</table>
</form>
1. <h1>Write a new post</h1>
2. <form method="post" action="<?php echo $html->url('/posts/add'); ?>">
3. <table>
4. <tr>
5. <td>Title:</td>
6. <td><?php echo $html->input('Post/title')?></td>
7. </tr>
8. <tr>
9. <td>Body:</td>
10. <td><?php echo $html->textarea('Post/body')?></td>
11. </tr>
12. <tr>
13. <td>Related Tags:</td>
14. <td><?php echo $html->selectTag('Tag/Tag', $tags, null,
array('multiple' => 'multiple')) ?>
15. </td>
16. </tr>
17. <tr>
18. <td colspan="2">
19. <?php echo $html->hidden('Post/user_id', array('value' => $session-
>read('User.id')))?>
20. <?php echo $html->hidden('Post/status' , array('value' => '0'))?>
21. <?php echo $html->submit('Save Post')?>
22. </td>
23. </tr>
24. </table>
25. </form>
In order for a call to $this->Post->save() in the controller to save the links between this new Post
and its associated Tags, the name of the field must be in the form "Tag/Tag" (the rendered name
attribute would look something like 'data[ModelName][ModelName][]'). The submitted data
must be a single ID, or an array of IDs of linked records. Because we're using a multiple select
here, the submitted data for Tag/Tag will be an array of IDs.
The $tags variable here is just an array where the keys are the IDs of the possible Tags, and the
values are the displayed names of the Tags in the multi-select element.
Changing Associations on the Fly using bindModel() and unbindModel()
You might occasionally wish to change model association information for exceptional situations
when building your application. If your association settings in the model file are giving you too
much (or not enough) information, you can use two model functions to bind and unbind model
associations for your next find.
Let's set up a few models so we can see how bindModel() and unbindModel() work. We'll start
with two models:
leader.php and follower.php
Plain Text View

<?php

class Leader extends AppModel


{
var $name = 'Leader';

var $hasMany = array(


'Follower' => array(
'className' => 'Follower',
'order' => 'Follower.rank'
)
);
}

?>

<?php

class Follower extends AppModel


{
var $name = 'Follower';
}

?>
1. <?php
2. class Leader extends AppModel
3. {
4. var $name = 'Leader';
5. var $hasMany = array(
6. 'Follower' => array(
7. 'className' => 'Follower',
8. 'order' => 'Follower.rank'
9. )
10. );
11. }
12. ?>
13.
14. <?php
15. class Follower extends AppModel
16. {
17. var $name = 'Follower';
18. }
19. ?>
Now, in a LeadersController, we can use the find() method in the Leader Model to come up with
a Leader and its associated followers. As you can see above, the association array in the Leader
model defines a "Leader hasMany Followers" relationship. For demonstration purposes, let's use
unbindModel() to remove that association mid-controller.
leaders_controller.php (partial)
Plain Text View

function someAction()
{
//This fetches Leaders, and their associated Followers
$this->Leader->findAll();

//Let's remove the hasMany...


$this->Leader->unbindModel(array('hasMany' => array('Follower')));

//Now a using a find function will return Leaders, with no Followers


$this->Leader->findAll();

//NOTE: unbindModel only affects the very next find function.


//An additional find call will use the configured association information.

//We've already used findAll() after unbindModel(), so this will fetch


//Leaders with associated Followers once again...
$this->Leader->findAll();
}
1. function someAction()
2. {
3. //This fetches Leaders, and their associated Followers
4. $this->Leader->findAll();
5. //Let's remove the hasMany...
6. $this->Leader->unbindModel(array('hasMany' => array('Follower')));
7.
8. //Now a using a find function will return Leaders, with no Followers
9. $this->Leader->findAll();
10. //NOTE: unbindModel only affects the very next find function.
11. //An additional find call will use the configured association
information.
12. //We've already used findAll() after unbindModel(), so this will fetch
13. //Leaders with associated Followers once again...
14. $this->Leader->findAll();
15. }
The unbindModel() function works similarly with other associations: just change the name of the
association type and model classname. The basic usage for unbindModel() is:
Generic unbindModel() example
Plain Text View

$this->Model->unbindModel(array('associationType' =>
array('associatedModelClassName')));
1. $this->Model->unbindModel(array('associationType' =>
array('associatedModelClassName')));
Now that we've successfully removed an association on the fly, let's add one. Our as-of-yet
unprincipled Leader needs some associated Principles. The model file for our Principle model is
bare, except for the var $name statement. Let's associate some Principles to our Leader on the fly
(but only for just the following find function call):
leaders_controller.php (partial)
Plain Text View

function anotherAction()
{
//There is no Leader hasMany Principles in the leader.php model file, so
//a find here, only fetches Leaders.
$this->Leader->findAll();

//Let's use bindModel() to add a new association to the Principle model:


$this->Leader->bindModel(
array('hasMany' => array(
'Principle' => array(
'className' => 'Principle'
)
)
)
);
//Now that we're associated correctly, we can use a single find function
//to fetch Leaders with their associated principles:
$this->Leader->findAll();
}
1. function anotherAction()
2. {
3. //There is no Leader hasMany Principles in the leader.php model file, so
4. //a find here, only fetches Leaders.
5. $this->Leader->findAll();
6. //Let's use bindModel() to add a new association to the Principle model:
7. $this->Leader->bindModel(
8. array('hasMany' => array(
9. 'Principle' => array(
10. 'className' => 'Principle'
11. )
12. )
13. )
14. );
15. //Now that we're associated correctly, we can use a single find function
16. //to fetch Leaders with their associated principles:
17. $this->Leader->findAll();
18. }
The bindModel() function can be handy for creating new assocations, but it can also be useful if
you want to change the sorting or other parameters in a given association on the fly.
There you have it. The basic usage for bindModel is to encapsulate a normal association array
inside an array who's key is named after the type of assocation you are trying to create:
Generic bindModel() example
Plain Text View

$this->Model->bindModel(
array('associationName' => array(
'associatedModelClassName' => array(
// normal association keys go here...
)
)
)
);
1. $this->Model->bindModel(
2. array('associationName' => array(
3. 'associatedModelClassName' => array(
4. // normal association keys go here...
5. )
6. )
7. )
8. );
Please note that your tables will need to be keyed correctly (or association array properly
configured) to bind models on the fly.

8 Controllers
• Edit
• Comments (0)
• History

What is a controller?
A controller is used to manage the logic for a certain section of your application. Most
commonly, controllers are used to manage the logic for a single model. For example, if you were
building a site that manages a video collection, you might have a VideosController and a
RentalsController managing your videos and rentals, respectively. In Cake, controller names
are always plural.
Your application's controllers are classes that extend the Cake AppController class, which in turn
extends a core Controller class. Controllers can include any number of actions: functions used in
your web application to display views.
The AppController class can be defined in /app/app_controller.php and it should contain
methods that are shared between two or more controllers. It itself extends the Controller class
which is a standard Cake library.
An action is a single functionality of a controller. It is run automatically by the Dispatcher if an
incoming page request specifies it in the routes configuration. Returning to our video collection
example, our VideosController might contain the view(), rent(), and search() actions. The
controller would be found in /app/controllers/videos_controller.php and contain:
Plain Text View

class VideosController extends AppController


{
function view($id)
{
//action logic goes here..
}

function rent($customer_id, $video_id)


{
//action logic goes here..
}
function search($query)
{
//action logic goes here..
}
}
1. class VideosController extends AppController
2. {
3. function view($id)
4. {
5. //action logic goes here..
6. }
7. function rent($customer_id, $video_id)
8. {
9. //action logic goes here..
10. }
11. function search($query)
12. {
13. //action logic goes here..
14. }
15. }
You would be able to access these actions using the following example URLs:
Plain Text View

http://www.example.com/videos/view/253
http://www.example.com/videos/rent/5124/0-235253
http://www.example.com/videos/search/hudsucker+proxy
1. http://www.example.com/videos/view/253
2. http://www.example.com/videos/rent/5124/0-235253
3. http://www.example.com/videos/search/hudsucker+proxy
But how would these pages look? You would need to define a view for each of these actions -
check it out in the next chapter, but stay with me: the following sections will show you how to
harness the power of the Cake controller and use it to your advantage. Specifically, you'll learn
how to have your controller hand data to the view, redirect the user, and much more.

Controller Functions
While this section will treat most of the often-used functions in Cake's Controller, it's important
to remember to use http://api.cakephp.org for a full reference.
Interacting with your Views
• set
• string $var
• mixed $value
This function is the main way to get data from your controller to your view. You can use it to
hand over anything: single values, whole arrays, etc. Once you've used set(), the variable can be
accessed in your view: doing set('color', 'blue') in your controller makes $color available in the
view.
• validateErrors
Returns the number of errors generated by an unsuccessful save.
• validate
Validates the model data according to the model's validation rules. For more on validation, see
Chapter "Data Validation".
• render
• string $action
• string $layout
• string $file
You may not often need this function, because render is automatically called for you at the end
of each controller action, and the view named after your action is rendered. Alternatively, you
can call this function to render the view at any point in the controller logic.
User Redirection
• redirect
• string $url
Tell your users where to go using this function. The URL passed here can be a Cake internal
URL, or a fully qualified URL (http://...).
• flash
• string $message
• string $url
• int $pause
This function shows $message for $pause seconds inside of your flash layout (found in
app/views/layouts/flash.thtml) then redirects the user to the specified $url.
Cake's redirect() and flash() functions do not include an exit() call. If you wish your application
to halt after a redirect() or flash(), you'll need to include your own exit() call immediately after.
You may also want to return rather than exit(), depending on your situation (for example, if you
need some callbacks to execute).
Controller Callbacks
Cake controllers feature a number of callbacks you can use to insert logic before or after
important controller functions. To utilize this functionality, declare these functions in your
controller using the parameters and return values detailed here.
• beforeFilter
Called before every controller action. A useful place to check for active sessions and check roles.
• afterFilter
Called after every controller action.
• beforeRender
Called after controller logic, and just before a view is rendered.
Other Useful Functions
While these are functions part of Cake's Object class, they are also available inside the
Controller:
• requestAction
○ string $url
○ array $extra
This function calls a controller's action from any location and returns the rendered view. The $url
is a Cake URL (/controllername/actionname/params). If the $extra array includes a 'return' value,
AutoRender is automatically set to true for the controller action.
You can use requestAction to get data from another controller action, or get a fully rendered
view from a controller.
First, getting data from a controller is simple. You just use requestAction in the view where you
need the data.
Plain Text View

// Here is our simple controller:

class UsersController extends AppController


{
function getUserList()
{
return $this->User->findAll();
}
}
1. // Here is our simple controller:
2. class UsersController extends AppController
3. {
4. function getUserList()
5. {
6. return $this->User->findAll();
7. }
8. }
Imagine that we needed to create a simple table showing the users in the system. Instead of
duplicating code in another controller, we can get the data from UsersController::getUserList()
instead by using requestAction().
Plain Text View

class ProductsController extends AppController


{
function showUserProducts()
{
$this->set('users', $this->requestAction('/users/getUserList'));

// Now the $users variable in the view will have the data from
// UsersController::getUserList().
}
}

1. class ProductsController extends AppController


2. {
3. function showUserProducts()
4. {
5. $this->set('users', $this->requestAction('/users/getUserList'));
6. // Now the $users variable in the view will have the data from
7. // UsersController::getUserList().
8. }
9. }
10.
If you have an often used element in your application that is not static, you might want to use
requestAction() to inject it into your views. Let's say that rather than just passing the data from
UsersController::getUserList, we actually wanted to render that action's view (which might
consist of a table), inside another controller. This saves us from duplicating view code.
Plain Text View

class ProgramsController extends AppController


{
function viewAll()
{
$this->set('userTable', $this->requestAction('/users/getUserList',
array('return')));

// Now, we can echo out $userTable in this action's view to


// see the rendered view that is also available at /users/getUserList.
}
}
1. class ProgramsController extends AppController
2. {
3. function viewAll()
4. {
5. $this->set('userTable', $this->requestAction('/users/getUserList',
array('return')));
6. // Now, we can echo out $userTable in this action's view to
7. // see the rendered view that is also available at /users/getUserList.
8. }
9. }
Please note that actions called using requestAction() are rendered using an empty layout - this
way you don't have to worry about layouts getting rendered inside of layouts.
The requestAction() function is also useful in AJAX situations where a small element of a view
needs to be populated before or during an AJAX update.
• log
○ string $message
○ int $type = LOG_ERROR
You can use this function to log different events that happen within your web application. Logs
can be found inside Cake's /tmp directory.
If the $type is equal to the PHP constant LOG_DEBUG, the message is written to the log as a
debug message. Any other type is written to the log as an error.
Plain Text View

// Inside a controller, you can use log() to write entries:


$this->log('Mayday! Mayday!');
//Log entry:
06-03-28 08:06:22 Error: Mayday! Mayday!
$this->log("Looks like {$_SESSION['user']} just logged in.", LOG_DEBUG);
//Log entry:
06-03-28 08:06:22 Debug: Looks like Bobby just logged in.
1. // Inside a controller, you can use log() to write entries:
2. $this->log('Mayday! Mayday!');
3. //Log entry:
4. 06-03-28 08:06:22 Error: Mayday! Mayday!
5. $this->log("Looks like {$_SESSION['user']} just logged in.", LOG_DEBUG);
6. //Log entry:
7. 06-03-28 08:06:22 Debug: Looks like Bobby just logged in.
• postConditions
○ array $data
A method to which you can pass $this->data, and it will pass back an array formatted as a model
conditions array.
For example, if I have a person search form:
Plain Text View

// app/views/people/search.thtml:

<?php echo $html->input('Person/last_name'); ?>


1. // app/views/people/search.thtml:
2. <?php echo $html->input('Person/last_name'); ?>
Submitting the form with this element would result in the following $this->data array:
Plain Text View

Array
(
[Person] => Array
(
[last_name] => Anderson
)
)
1. Array
2. (
3. [Person] => Array
4. (
5. [last_name] => Anderson
6. )
7. )
At this point, we can use postConditions() to format this data to use in model:
Plain Text View

// app/controllers/people_controller.php:
$conditions = $this->postConditions($this->data);

// Yields an array looking like this:


Array
(
[Person.last_name] => Anderson
)

// Which can be used in model find operations:


$this->Person->findAll($conditions);
1. // app/controllers/people_controller.php:
2. $conditions = $this->postConditions($this->data);
3. // Yields an array looking like this:
4. Array
5. (
6. [Person.last_name] => Anderson
7. )
8. // Which can be used in model find operations:
9. $this->Person->findAll($conditions);

Controller Variables
Manipulating a few special variables inside of your controller allows you to take advantage of
some extra Cake functionality:
$name
PHP 4 doesn't like to give us the name of the current class in CamelCase. Use this variable to set
the correct CamelCased name of your class if you're running into problems.
$uses
Does your controller use more than one model? Your FragglesController will automatically load
$this->Fraggle, but if you want access to $this->Smurf as well, try adding something like the
following to your controller:
Plain Text View

var $uses = array('Fraggle','Smurf');


1. var $uses = array('Fraggle','Smurf');
Please notice how you also need to include your Fraggle model in the $uses array, even though it
was automatically available before.
$helpers
Use this variable to have your controller load helpers into its views. The HTML helper is
automatically loaded, but you can use this variable to specify a few others:
Plain Text View

var $helpers = array('Html','Ajax','Javascript');


1. var $helpers = array('Html','Ajax','Javascript');
Remember that you will need to include the HtmlHelper in the $helpers array if you intend to use
it. It is normally available by default, but if you define $helpers without it, you'll get error
messages in your views.
$layout
Set this variable to the name of the layout you would like to use for this controller.
$autoRender
Setting this to false will stop your actions from automatically rendering.
$beforeFilter
If you'd like a bit of code run every time an action is called (and before any of that action code
runs), use $beforeFilter. This functionality is really nice for access control - you can check to see
a user's permissions before any action takes place. Just set this variable using an array containing
the controller action(s) you'd like to run:
Plain Text View

class ProductsController extends AppController


{
var $beforeFilter = array('checkAccess');

function checkAccess()
{
//Logic to check user identity and access would go here....
}

function index()
{
//When this action is called, checkAccess() is called first.
}
}
1. class ProductsController extends AppController
2. {
3. var $beforeFilter = array('checkAccess');
4. function checkAccess()
5. {
6. //Logic to check user identity and access would go here....
7. }
8. function index()
9. {
10. //When this action is called, checkAccess() is called first.
11. }
12. }
$components
Just like $helpers and $uses, this variable is used to load up components you will need:
Plain Text View

var $components = array('acl');


1. var $components = array('acl');

Controller Parameters
Controller parameters are available at $this->params in your Cake controller. This variable is
used to get data into the controller and provide access to information about the current request.
The most common usage of $this->params is to get access to information that has been handed to
the controller via POST or GET operations.
$this->data
Used to handle POST data sent from HTML Helper forms to the controller.
Plain Text View

// A HTML Helper is used to create a form element

$html->input('User/first_name');

// When rendered as HTML it looks like:

<input name="data[User][first_name]" value="" type="text" />

// And when submitted to the controller via POST,


// shows up in $this->data['User']['first_name']

Array
(
[data] => Array
(
[User] => Array
(
[username] => mrrogers
[password] => myn3ighb0r
[first_name] => Mister
[last_name] => Rogers
)

)
)
1. // A HTML Helper is used to create a form element
2. $html->input('User/first_name');
3. // When rendered as HTML it looks like:
4. <input name="data[User][first_name]" value="" type="text" />
5. // And when submitted to the controller via POST,
6. // shows up in $this->data['User']['first_name']
7. Array
8. (
9. [data] => Array
10. (
11. [User] => Array
12. (
13. [username] => mrrogers
14. [password] => myn3ighb0r
15. [first_name] => Mister
16. [last_name] => Rogers
17. )
18. )
19. )
$this->params['form']
Any POST data from any form is stored here, including information also found in $_FILES.
$this->params['bare']
Stores '1' if the current layout is bare, '0' if not.
$this->params['ajax']
Stores '1' if the current layout is ajax, '0' if not.
$this->params['controller']
Stores the name of the current controller handling the request. For example, if the URL
/posts/view/1 was called, $this->params['controller'] would equal "posts".
$this->params['action']
Stores the name of the current action handling the request. For example, if the URL
/posts/view/1 was called, $this->params['action'] would equal "view".
$this->params['pass']
Stores the GET query string passed with the current request. For example, if the URL
/posts/view/?var1=3&var2=4 was called, $this->params['pass'] would equal "?var1=3&var2=4".
$this->params['url']
Stores the current URL requested, along with key-value pairs of get variables. For example, if
the URL /posts/view/?var1=3&var2=4 was called, $this->params['url'] would look like this:
Plain Text View

[url] => Array


(
[url] => posts/view
[var1] => 3
[var2] => 4
)
1. [url] => Array
2. (
3. [url] => posts/view
4. [var1] => 3
5. [var2] => 4
6. )
« Models | Views »

9 Views
• Edit
• Comments (1)
• History
A view is a page template, usually named after an action. For example, the view for
PostsController::add() would be found at /app/views/posts/add.thtml. Cake views are quite
simply PHP files, so you can use any PHP code inside them. Although most of your view files
will contain HTML, a view could be any perspective on a certain set of data, be it XML, and
image, etc.
In the view template file, you can use the data from the corresponding Model. This data is passed
as an array called $data. Any data that you've handed to the view using set() in the controller is
also now available in your view.
The HTML helper is available in every view by default, and is by far the most commonly used
helper in views. It is very helpful in creating forms, including scripts and media, linking and
aiding in data validation. Please see section 1 in Chapter "Helpers" for a discussion on the
HTML helper.
Most of the functions available in the views are provided by Helpers. Cake comes with a great
set of helpers (discussed in Chapter "Helpers"), and you can also include your own. Because
views shouldn't contain much logic, there aren't many well used public functions in the view
class. One that is helpful is renderElement(), which will be discussed in section 1.2.
Layouts
A layout contains all the presentational code that wraps around a view. Anything you want to see
in all of your views should be placed in your layout.
Layout files are placed in /app/views/layouts. Cake's default layout can be overridden by
placing a new default layout at /app/views/layouts/default.thtml. Once a new default layout has
been created, controller view code is placed inside of the default layout when the page is
rendered.
When you create a layout, you need to tell Cake where to place your controller view code: to do
so, make sure your layout includes a place for $content_for_layout (and optionally,
$title_for_layout). Here's an example of what a default layout might look like:
Plain Text View

<!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>
<title><?php echo $title_for_layout?></title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
</head>
<body>

<!-- If you'd like some sort of menu to show up on all of your views, include
it here -->
<div id="header">
<div id="menu">...</div>
</div>

<!-- Here's where I want my views to be displayed -->


<?php echo $content_for_layout ?>

<!-- Add a footer to each displayed page -->


<div id="footer">...</div>

</body>
</html>
1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3. <html xmlns="http://www.w3.org/1999/xhtml">
4. <head>
5. <title><?php echo $title_for_layout?></title>
6. <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
7. </head>
8. <body>
9. <!-- If you'd like some sort of menu to show up on all of your views,
include it here -->
10. <div id="header">
11. <div id="menu">...</div>
12. </div>
13. <!-- Here's where I want my views to be displayed -->
14. <?php echo $content_for_layout ?>
15.
16. <!-- Add a footer to each displayed page -->
17. <div id="footer">...</div>
18. </body>
19. </html>
To set the title for the layout, it's easiest to do so in the controller, using the $pageTitle controller
variable.
Plain Text View

class UsersController extends AppController


{
function viewActive()
{
$this->pageTitle = 'View Active Users';
}
}
1. class UsersController extends AppController
2. {
3. function viewActive()
4. {
5. $this->pageTitle = 'View Active Users';
6. }
7. }
You can create as many layouts as you wish for your Cake site, just place them in the
app/views/layouts directory, and switch between them inside of your controller actions using the
controller's $layout variable, or setLayout() function.
For example, if a section of my site included a smaller ad banner space, I might create a new
layout with the smaller advertising space and specify it as the layout for all controller's actions
using something like:
Plain Text View
var $layout = 'default_small_ad';
1. var $layout = 'default_small_ad';
Elements
Many applications have small blocks of presentational code that needs to be repeated from page
to page, sometimes in different places in the layout. Cake can help you repeat parts of your
website that need to be reused. These reusable parts are called Elements. Ads, help boxes,
navigational controls, extra menus, and callouts are often implemented in Cake as elements. An
Element is basically a mini-view that can be included in other Views.
Elements live in the /app/views/elements/ folder, and have the .thtml filename extension.
The Element, by default, has access to any data declared for use in the View.
Rendering an Element
Plain Text View

<?php echo $this->renderElement('helpbox'); ?>


1. <?php echo $this->renderElement('helpbox'); ?>
You can also directly hand data to an Element for use, by passing an array of data as the second
parameter of the renderElement method.
Calling an Element passing a data array
Plain Text View

<?php echo
$this->renderElement('helpbox', array("helptext" => "Oh, this text is very
helpful."));
?>
1. <?php echo
2. $this->renderElement('helpbox', array("helptext" => "Oh, this text is
very helpful."));
3. ?>
Inside the Element file, all the passed variables are available as the names of the keys of the
passed array (much like how set() in the controller works with the views). In the above example,
the /app/views/elements/helpbox.thtml file can use the $helptext variable. Of course, it would
be more useful to pass an array to the Element.
Elements can be used to make a View more readable, placing the rendering of repeating elements
in its own file. They can also help you re-use content fragments in your website.
Error Views
There are a number of different situations where CakePHP needs to show some sort of error
message. Many times during development you can see these error views - when you try to access
a controller or view that doesn't exist, for example. You can customize these views by creating
special view files in app/views/error.
Here are the error views that are supported by CakePHP:
Error view files (app/views/error)
Plain Text View

error404.thtml
missing_action.thtml
missing_component_class.thtml
missing_component_file.thtml
missing_connection.thtml
missing_controller.thtml
missing_helper_class.thtml
missing_helper_file.thtml
missing_layout.thtml
missing_model.thtml
missing_scaffolddb.thtml
missing_table.thtml
missing_view.thtml
private_action.thtml
scaffold_error.thtml
1. error404.thtml
2. missing_action.thtml
3. missing_component_class.thtml
4. missing_component_file.thtml
5. missing_connection.thtml
6. missing_controller.thtml
7. missing_helper_class.thtml
8. missing_helper_file.thtml
9. missing_layout.thtml
10. missing_model.thtml
11. missing_scaffolddb.thtml
12. missing_table.thtml
13. missing_view.thtml
14. private_action.thtml
15. scaffold_error.thtml
To customize any of these error views, create the file in app/views/error. When an error occurs,
the respective error view will be displayed. You can copy any of these error views from
cake/libs/view/templates/errors in the core to use as examples, but remember not to edit these
files where they reside in the CakePHP core.
By default, most of these views are not shown when DEBUG is set to a value greater than 0. As
such, the main error view you'll need to focus on is the error404.thtml error view.
« Controllers | Components »
10 Components
• Edit
• Comments (0)
• History
Components are used to aid controllers in specific situations. Rather than extend Cake's core
libraries, special functionality can be made into components.
A guy named olle on the IRC channel once said: A component is a sharable little "controllerette".
We find that this is a good definition. The main goal in fact is: reusability. Components are to
controllers what helpers are to views. The main difference is that components encapsulate
business logic whereas helpers encapsulate presentation logic. This point actually is very
important, a common source of confusion for new Bakers when trying to achieve reusability: I'm
trying to do X, should this be a component or a helper?! Well, the answer is really simple, what
does X do? Does it do business logic or presentation logic, perhaps both? If it's business logic
then it's a component. If it's presentation logic then it's a helper. If it's both, then..well it's both a
component and a helper. An example of the later case would be an authentication system. You
would want to login, logout, restrict access, and test permissions of a user to a resource (an
action: add, edit, delete, or a url), this is business logic, so this authentication system should be a
component. But you also want to add some entries to the main menu when the user is logged in,
and this is presentation logic.

Creating your own


To create a component, add a file in app/controllers/components/ directory.
Let us assume you created foo.php. Inside of the file you need to define a class that corresponds
to the file name (appending the word 'Component' to the file name). So in our case you would
create the following contents:
A simple component
Plain Text View

class FooComponent extends Object


{
var $someVar = null;
var $controller = true;

function startup(&$controller)
{
// This method takes a reference to the controller which is loading
it.
// Perform controller initialization here.
}

function doFoo()
{
$this->someVar = 'foo';
}
}
1. class FooComponent extends Object
2. {
3. var $someVar = null;
4. var $controller = true;
5.
6. function startup(&$controller)
7. {
8. // This method takes a reference to the controller which is loading it.
9. // Perform controller initialization here.
10. }
11.
12. function doFoo()
13. {
14. $this->someVar = 'foo';
15. }
16. }
The startup() function is used by the Dispatcher during the CakePHP bootstrap process. Its a
constructor-like function that allows a component access to its controller. If you do not want this
function to be used or called, set the class variable $disableStartup to true.
Now, to use your component, you need to add the following code in your controller's definition:
Plain Text View

var $components = array('Foo');


1. var $components = array('Foo');
Inside of that controller you could now use:
Plain Text View

$this->Foo->doFoo();
1. $this->Foo->doFoo();
A component gets access to the controller that loaded it through the startup() method shown
above. This method is called immediately after Controller::beforeFilter(). This allows you to set
component properties in the beforeFilter method, which the component can act on in it’s
startup() method.
Because CakePHP loads models in a lazy fashion, it's usually not a good idea to create model
instances in components. If you need model data in a component, it's best to pass that data in
through one of the component's methods:
Plain Text View

<?php

class UsersController extends AppController


{
var $uses = array('Apple');
var $components = array('Foo');

function index()
{
$data = $this->Foo->doFoo($this->Apple->findAll());
}
}

?>
1. <?php
2. class UsersController extends AppController
3. {
4. var $uses = array('Apple');
5. var $components = array('Foo');
6. function index()
7. {
8. $data = $this->Foo->doFoo($this->Apple->findAll());
9. }
10. }
11. ?>
You can also use other components inside your component. You simply have to declare in your
component which components you want to use. In the example below it is the session
component.
Plain Text View

var $components = array('Session');


1. var $components = array('Session');

Making your components public


If you think your component can be helpful to others, add it to the Bakery. A component that
becomes increasingly useful for the community may some day be included in the core
distribution.
Also check the snippet archive for user committed components.
« Views | Helpers »

11 Helpers
• Edit
• Comments (0)
• History
Helpers are meant to provide functions that are commonly needed in views to format and present
data in useful ways.

HTML
Introduction
The HTML helper is one of Cake's ways of making development less monotonous and more
rapid. The HTML helper has two main goals: to aid in the insertion of often-repeated sections of
HTML code, and to aid in the quick-and-easy creation of web forms. The following sections will
walk you through the most important functions in the helper, but remember
http://api.cakephp.org should always be used as a final reference.
Many of the functions in the HTML helper make use of a HTML tag definition file called
tags.ini.php. Cake's core configuration contains a tags.ini.php, but if you'd like to make some
changes, create a copy of /cake/config/tags.ini.php and place it in your /app/config/ folder. The
HTML helper uses the tag definitions in this file to generate tags you request. Using the HTML
helper to create some of your view code can be helpful, as a change to the tags.ini.php file will
result in a site-wide cascading change.
Additionally, if AUTO_OUTPUT is set to true in your core config file for your application
(/app/config/core.php), the helper will automatically output the tag, rather than returning the
value. This has been done in an effort to assuage those who dislike short tags (<?= ?>) or lots of
echo() calls in their view code. Functions that include the $return parameter allow you to force-
override the settings in your core config. Set $return to true if you'd like the HTML helper to
return the HTML code regardless of any AUTO_OUTPUT settings.
HTML helper functions also include a $htmlAttributes parameter, that allow you to tack on any
extra attributes on your tags. For example, if you had a tag you'd like to add a class attribute to,
you'd pass this as the $htmlAttribute value:
Plain Text View

array('class'=>'someClass')
1. array('class'=>'someClass')
Inserting Well-Formatted elements
If you'd like to use Cake to insert well-formed and often-repeated elements in your HTML code,
the HTML helper is great at doing that. There are functions in this helper that insert media, aid
with tables, and there's even guiListTree which creates an unordered list based on a PHP array.
• charset
• string $charset
• boolean $return
This is used to generate a charset META-tag.
• css
• string $path
• string $rel = 'stylesheet'
• array $htmlAttributes
• boolean $return = false
Creates a link to a CSS stylesheet. The $rel parameter allows you to provide a rel= value for the
tag.
• image
• string $path
• array $htmlAttributes
• boolean $return = false
Renders an image tag. The code returned from this function can be used as an input for the link()
function to automatically create linked images.
• link
• string $title
• string $url
• array $htmlAttributes
• string $confirmMessage = false
• boolean $escapeTitle = true
• boolean $return = false
Use this function to create links in your view. $confirmMessage is used when you need a
JavaScript confirmation message to appear once the link is clicked. For example, a link that
deletes an object should probably have a "Are you sure?" type message to confirm the action
before the link is activated. Set $escapeTitle to true if you'd like to have the HTML helper escape
the data you handed it in the $title variable.
• tableHeaders
• array $names
• array $tr_options
• array $th_options
Used to create a formatted table header.
• tableCells
• array $data
• array $odd_tr_options
• array $even_tr_options
Used to create a formatted set of table cells.
• guiListTree
• array $data
• array $htmlAttributes
• string $bodyKey = 'body'
• string $childrenKey = 'children'
• boolean $return = false
Generates a nested unordered list tree from an array.
Forms and Validation
The HTML helper really shines when it comes to quickening your form code in your views. It
generates all your form tags, automatically fills values back in during error situations, and spits
out error messages. To help illustrate, let's walk through a quick example. Imagine for a moment
that your application has a Note model, and you want to create controller logic and a view to add
and edit Note objects. In your NotesController, you would have an edit action that might look
something like the following:
Edit Action inside of the NotesController
Plain Text View

function edit($id)
{
//First, let's check to see if any form data has been
//submitted to the action.
if (!empty($this->data['Note']))
{
//Here's where we try to validate the form data (see Chap. 12)
//and save it
if ($this->Note->save($this->data['Note']))
{
//If we've successfully saved, take the user
//to the appropriate place
$this->flash('Your information has been saved.', '/notes/edit/' .
$id);
exit();
}
else
{

//Generate the error messages for the appropriate fields


//this is not really necessary as save already does this, but it is
an example
//call $this->Note->validates($this->data['Note']); if you are not
doing a save
//then use the method below to populate the tagErrorMsg() helper
method
$this->validateErrors($this->Note);

//And render the edit view code


$this->render();
}
}

// If we haven't received any form data, get the note we want to edit, and
hand
// its information to the view
$this->set('note', $this->Note->find("id = $id"));
$this->render();
}
1. function edit($id)
2. {
3. //First, let's check to see if any form data has been
4. //submitted to the action.
5. if (!empty($this->data['Note']))
6. {
7. //Here's where we try to validate the form data (see Chap. 12)
8. //and save it
9. if ($this->Note->save($this->data['Note']))
10. {
11. //If we've successfully saved, take the user
12. //to the appropriate place
13. $this->flash('Your information has been saved.', '/notes/edit/' . $id);
14. exit();
15. }
16. else
17. {
18. //Generate the error messages for the appropriate fields
19. //this is not really necessary as save already does this, but it is an
example
20. //call $this->Note->validates($this->data['Note']); if you are not
doing a save
21. //then use the method below to populate the tagErrorMsg() helper method
22. $this->validateErrors($this->Note);
23. //And render the edit view code
24. $this->render();
25. }
26. }
27. // If we haven't received any form data, get the note we want to edit,
and hand
28. // its information to the view
29. $this->set('note', $this->Note->find("id = $id"));
30. $this->render();
31. }
Once we've got our controller set up, let's look at the view code (which would be found in
app/views/notes/edit.thtml). Our Note model is pretty simple at this point as it only contains an
id, a submitter's id and a body. This view code is meant to display Note data and allow the user
to enter new values and save that data to the model.
The HTML helper is available in all views by default, and can be accessed using $html.
Specifically, let's just look at the table where the guts of the form are found:
Edit View code (edit.thtml) sample
Plain Text View

<!-- This tag creates our form tag -->

<?php echo $html->formTag('/notes/edit/' . $html->tagValue('Note/id')) ?>

<table cellpadding="10" cellspacing="0">


<tr>
<td align="right">Body: </td>
<td>

<!-- Here's where we use the HTML helper to render the text
area tag and its possible error message the $note
variable was created by the controller, and contains
the data for the note we're editing. -->
<?php echo
$html->textarea('Note/body', array('cols'=>'60', 'rows'=>'10'));
?>
<?php echo $html->tagErrorMsg('Note/body',
'Please enter in a body for this note.') ?>
</td>
</tr>
<tr>
<td></td>
<td>

<!-- We can also use the HTML helper to include


hidden tags inside our table -->

<?php echo $html->hidden('Note/id')?>


<?php echo $html->hidden('note/submitter_id', $this->controller-
>Session->read('User.id'))?>
</td>
</tr>
</table>

<!-- And finally, the submit button-->


<?php echo $html->submit()?>

</form>
1. <!-- This tag creates our form tag -->
2. <?php echo $html->formTag('/notes/edit/' . $html->tagValue('Note/id'))
?>
3.
4. <table cellpadding="10" cellspacing="0">
5. <tr>
6. <td align="right">Body: </td>
7. <td>
8. <!-- Here's where we use the HTML helper to render the text
9. area tag and its possible error message the $note
10. variable was created by the controller, and contains
11. the data for the note we're editing. -->
12. <?php echo
13. $html->textarea('Note/body', array('cols'=>'60', 'rows'=>'10'));
14. ?>
15. <?php echo $html->tagErrorMsg('Note/body',
16. 'Please enter in a body for this note.') ?>
17. </td>
18. </tr>
19. <tr>
20. <td></td>
21. <td>
22. <!-- We can also use the HTML helper to include
23. hidden tags inside our table -->
24. <?php echo $html->hidden('Note/id')?>
25. <?php echo $html->hidden('note/submitter_id', $this->controller-
>Session->read('User.id'))?>
26. </td>
27. </tr>
28. </table>
29. <!-- And finally, the submit button-->
30. <?php echo $html->submit()?>
31.
32. </form>
Most of the form tag generating functions (along with tagErrorMsg) require you to supply a
$fieldName. This $fieldName lets Cake know what data you are passing so that it can save and
validate the data correclty. The string passed in the $fieldName parameter is in the form
"modelname/fieldname." If you were going to add a new title field to our Note, you might add
something to the view that looked like this:
Plain Text View

<?php echo $html->input('Note/title') ?><br />


<?php echo $html->tagErrorMsg('Note/title', 'Please supply a title for this
note.')?>
1. <?php echo $html->input('Note/title') ?><br />
2. <?php echo $html->tagErrorMsg('Note/title', 'Please supply a title for
this note.')?>
Error messages displayed by the tagErrorMsg() function are wrapped in <div
class="error_message"></div> for easy CSS styling.
Here are the form tags the HTML helper can generate (most of them are straightforward):
• submit
• string $buttonCaption
• array $htmlAttributes
• boolean $return = false
• password
• string $fieldName
• array $htmlAttributes
• boolean $return = false
• textarea
• string $fieldName
• array $htmlAttributes
• boolean $return = false
• checkbox
• string $fieldName
• string $title = null
• array $htmlAttributes
• boolean $return = false
• file
• string $fieldName
• array $htmlAttributes
• boolean $return = false
• hidden
• string $fieldName
• array $htmlAttributes
• boolean $return = false
• input
• string $fieldName
• array $htmlAttributes
• boolean $return = false
• radio
• string $fieldName
• array $options
• array $inbetween
• array $htmlAttributes
• boolean $return = false
• tagErrorMsg
• string $fieldName
• string $message
The HTML helper also includes a set of functions that aid in creating date-related option tags.
The $tagName parameter should be handled in the same way as the $fieldName parameter. Just
provide the name of the field this date option tag is relevant to. Once the data is processed, you'll
see it in your controller with the part of the date it handles concatenated to the end of the field
name. For example, if my Note had a deadline field that was a date, and my dayOptionTag
$tagName parameter was set to 'note/deadline', the day data would show up in the $params
variable once the form has been submitted to a controller action:
Plain Text View

$this->data['Note']['deadline_day']
1. $this->data['Note']['deadline_day']
You can then use this information to concatenate the time data in a format that is friendly to your
current database configuration. This code would be placed just before you attempt to save the
data, and saved in the $data array used to save the information to the model.
Pre-populating a form element is done by supplying a 'value' key-value pair in the
$htmlAttributes parameter. For text-based fields, the value will be shown in the form element.
For discrete form elements, supply the id or key of the element you'd like to have be selected by
default.
Plain Text View

//Sets the radio element with 'Complete' selected by default.<br />


$html->radio('Note/status', array('1' => 'Complete', '2' => 'In Progress'),
null, array('value' => '1'));
1. //Sets the radio element with 'Complete' selected by default.<br />
2. $html->radio('Note/status', array('1' => 'Complete', '2' => 'In
Progress'), null, array('value' => '1'));

Concatenating time data before saving a model (excerpt from NotesController)


Plain Text View

function edit($id)
{
//First, let's check to see if any form data has been submitted to the
action.
if (!empty($this->data['Note']))
{

//Concatenate time data for storage...


$this->data['Note']['deadline'] =
$this->data['Note']['deadline_year'] . "-" .
$this->data['Note']['deadline_month'] . "-" .
$this->data['Note']['deadline_day'];
//Here's where we try to validate the form data (see Chap. 10) and
save it
if ($this->Note->save($this->data['Note']))
{

...
1. function edit($id)
2. {
3. //First, let's check to see if any form data has been submitted to the
action.
4. if (!empty($this->data['Note']))
5. {
6. //Concatenate time data for storage...
7. $this->data['Note']['deadline'] =
8. $this->data['Note']['deadline_year'] . "-" .
9. $this->data['Note']['deadline_month'] . "-" .
10. $this->data['Note']['deadline_day'];
11. //Here's where we try to validate the form data (see Chap. 10) and save
it
12. if ($this->Note->save($this->data['Note']))
13. {
14. ...
1. dayOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)
2. yearOptionTag ($tagName, $value=null, $minYear=null, $maxYear=null,
$selected=null, $optionAttr=null)
3. monthOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)
4. hourOptionTag ($tagName, $value=null, $format24Hours=false, $selected=null,
$optionAttr=null)
5. minuteOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)
6. meridianOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)
7. dateTimeOptionTag ($tagName, $dateFormat= 'DMY', $timeFormat= '12',
$selected=null, $optionAttr=null)

AJAX
The Cake Ajax helper utilizes the ever-popular Prototype and script.aculo.us libraries for Ajax
operations and client side effects. In order to use this helper, you must have a current version of
the JavaScript libraries from http://script.aculo.us placed in /app/webroot/js/. In addition, any
views that plan to use the Ajax Helper will need to include those libraries.
Most of the functions in this helper expect a special $options array as a parameter. This array is
used to specify different things about your Ajax operation. Here are the different values you can
specify:
AjaxHelper Options
General Options
url The URL for the action you want to be called

'frequenc The number of seconds between remoteTimer() or observeField() checks


y' are made.

The DOM ID of the element you wish to update with the results of an Ajax
'update'
operation.

The DOM ID of the form element you wish to serialize and send with an
'with'
Ajax form submission.

Either 'asynchronous' (default), or 'synchronous'. Allows you to pick


'type'
between operation types.

Callbacks
JavaScript code to be executed at certain times during the XMLHttpRequest process.
JS code to be executed when the remote document is being loaded with
'loading'
data by the browser.

JS code to be executed when the browser has finished loading the remote
'loaded'
document.

'interacti JS code to be executed when the user can interact with the remote
ve' document, even though it has not finished loading.

'complete
JS code to be called when the XMLHttpRequest is complete.
'

Text to be displayed in a confirmation dialog before a XMLHttpRequest


'confirm'
action begins.

'condition
JS condition to be met before the XMLHttpRequest is initiated.
'

'before' JS code to be called before request is initiated.

JS code to be called immediately after request was initiated and before


'after'
'loading'

Here are the helper's functions for making Ajax in Cake quick and easy:
• link
• string $title
• string $href
• array $options
• boolean $confirm
• boolean $escapeTitle
Displays linked text $title, which retrieves the remote document at $options['url'] and updates the
DOM element $options['update']. Callbacks can be used with this function.
• remoteFunction
• array $options
This function creates the JavaScript needed to make a remote call. It is primarily used as a helper
for linkToRemote. This isn't often used unless you need to generate some custom scripting.
• remoteTimer
• array $options
Periodically calls the specified action at $options['url'], every $options['frequency'] seconds
(default is 10). Usually used to update a specified div (specified by $options['update']) with the
results of the remote call. Callbacks can be used with this function.
• form
• string $action
• string $type
• array $options
Returns a form tag that will submit to the action at $action using XMLHttpRequest in the
background instead of the regular reload-required POST submission. The form data from this
form will act just as a normal form data would (i.e. it will be available in $this->params['form']).
The DOM element specified by $options['update'] will be updated with the resulting remote
document. Callbacks can be used with this function.
• observeField
• string $field_id
• array $options
Observes the field with the DOM ID specified by $field_id (every $options['frequency'] seconds)
and calls the action at $options['url'] when its contents have changed. You can update a DOM
element with ID $options['update'] or specify a form element using $options['with'] as well.
Callbacks can be used with this function.
• observeForm
• string $form_id
• array $options
Works the same as observeField(), only this observes all the elements in a given form.
• autoComplete
• string $field
• string $url
• array $options
Renders a text field with ID $field with autocomplete. The action at $url should be able to return
the autocomplete terms: basically, your action needs to spit out an unordered list (<ul></ul>)
with list items that are the auto complete terms. If you wanted an autocomplete field that
retrieved the subjects of your blog posts, your controller action might look something like:
Plain Text View

function autocomplete ()
{
$this->set('posts',
$this->Post->findAll(
"subject LIKE '{$this->data['Post']['subject']}'")
);
$this->layout = "ajax";
}
1. function autocomplete ()
2. {
3. $this->set('posts',
4. $this->Post->findAll(
5. "subject LIKE '{$this->data['Post']['subject']}'")
6. );
7. $this->layout = "ajax";
8. }
And your view for the autocomplete() action above would look something like:
Plain Text View

<ul>
<?php foreach($posts as $post): ?>
<li><?php echo $post['Post']['subject']; ?></li>
<?php endforeach; ?>
</ul>
1. <ul>
2. <?php foreach($posts as $post): ?>
3. <li><?php echo $post['Post']['subject']; ?></li>
4. <?php endforeach; ?>
5. </ul>
The actual auto-complete field as it would look in a view would look like this:
Plain Text View

<form action="/users/index" method="POST">


<?php echo $ajax->autoComplete('Post/subject', '/posts/autoComplete')?>
<?php echo $html->submit('View Post')?>
</form>
1. <form action="/users/index" method="POST">
2. <?php echo $ajax->autoComplete('Post/subject', '/posts/autoComplete')?>
3. <?php echo $html->submit('View Post')?>
4. </form>
The autoComplete() function will use this information to render a text field, and some divs that
will be used to show the autocomplete terms supplied by your action. You might also want to
style the view with something like the following:
Plain Text View

<style type="text/css">

div.auto_complete {
position :absolute;
width :250px;
background-color :white;
border :1px solid #888;
margin :0px;
padding :0px;
}

li.selected { background-color: #ffb; }

</style>
1. <style type="text/css">
2. div.auto_complete {
3. position :absolute;
4. width :250px;
5. background-color :white;
6. border :1px solid #888;
7. margin :0px;
8. padding :0px;
9. }
10. li.selected { background-color: #ffb; }
11. </style>
• drag
• string $id
• array $options
Makes the DOM element with ID $id draggable. There are some additional things you can
specify using $options (The version numbers refer to script.aculo.us versions):
(v1.0) Sets whether the element should only be draggable by an
'handle'
embedded handle. The value must be an element reference or element id.

'handle' (V1.5) As above, except now the value may be a string referencing a CSS
class value. The first child/grandchild/etc. element found within the
element that has this CSS class value will be used as the handle.

(V1.0) If set to true, the element returns to its original position when the
'revert'
drags ends.

(V1.5) Revert can also be an arbitrary function reference, called when the
'revert'
drag ends.

'constrai If set to horizontal or vertical, the drag will be constrained to take place
nt' only horizontally or vertically.

• drop
• string $id
• array $options
Makes the DOM element with ID $id drop-able. There are some additional things you can
specify using $options:
Set accept to a string or a JavaScript array of strings describing CSS
'accept' classes. The Droppable will only accept Draggables that have one or
more of these CSS classes.

The droppable element will only accept the draggable element if it is


'containme
contained in the given elements (or element ids). Can be a single
nt'
element or a JS array of elements.

If set to horizontal or vertical, the droppable will only react to a


'overlap' draggable element if its overlapping by more than 50% in the given
direction.

• dropRemote
• string $id
• array $options
• array $ajaxOptions
Used to create a drop target that initiates a XMLHttpRequest when a draggable element is
dropped on it. The $options are the same as in drop(), and the $ajaxOptions are the same as in
link().
• sortable
• string $id
• array $options
Makes a list or group of floated objects (specified by DOM element ID $id) sortable. The
$options array can configure your sorting as follows:
'tag' Sets the kind of tag (of the child elements of the container) that will be
made sortable. For UL and OL containers, this is LI, you have to provide
the tag kind for other sorts of child tags. Defaults to 'li'.

Further restricts the selection of child elements to only encompass


'only' elements with the given CSS class (or, if you provide an array of strings,
on any of the classes).

Either vertical(default) or horizontal. For floating sortables or horizontal


'overlap'
lists, choose horizontal. Vertical lists should use vertical.

'constraint' Restricts the movement of draggable elements, 'vertical' or 'horizontal'.

'containme Enables dragging and dropping between Sortables. Takes an array of


nt' elements or element-ids (of the containers).

Makes the created draggable elemetns use handles, see the handle
'handle'
option on drag().

• editor
• string $id
• string $url
• array $options
Creates an in-place ajax editor using the element with the DOM id supplied as the first
parameter. When implemented, the element will highlight on mouseOver, and will turn into a
single text input field when clicked. The second parameter is the URL that the edited data should
be sent to. The action should also return the updated contents of the element. Additional options
for the in-place editor can be found on the Script.aculo.us wiki.

Javascript
The JavaScript helper is used to aid the developer in outputting well-formatted Javascript-related
tags and data.
• codeBlock
• string $string
Used to return $script placed within JavaScript &lt;script&gt; tags.
• link
• string $url
Returns a JavaScript include tag pointing to the script referenced by $url.
• linkOut
• string $url
Same as link(), only the include tag assumes that the script referenced by $url is not hosted on
the same domain.
• escapeScript
• string $script
Escapes carriage returns and single and double quotes for JavaScript code segments.
• event
• string $object
• string $event
• string $observer
• boolean $useCapture
Attaches an event to an element. Used with the Prototype library.
• cacheEvents
Caches JavaScript events created with event().
• writeEvents
Writes cached events cached with cacheEvents().
• includeScript
• string $script

Number
The Number helper includes a few nice functions for formatting numerical data in your views.
• precision
• mixed $number
• int $precision = 3
Returns $number formatted to the level of precision specified by $precision.
• toReadableSize
• int $sizeInBytes
Returns a human readable size, given the $size supplied in bytes. Basically, you pass a number
of bytes in, and this function returns the appropriate human-readable value in KB, MB, GB, or
TB.
• toPercentage
• mixed $number
• int $precision = 2
Returns the given number formatted as a percentage, limited to the precision specified in
$precision.

Text
The Text Helper provides methods that a developer may need for outputting well formatted text
to the browser.
• highlight
• string $text
• string $highlighter = '<span class="highlight">\1</span>'
Returns $text, with every occurance or $phrase wrapped with the tags specified in $highlighter.
• stripLinks
• string $text
Returns $text, with all HTML links (&lt;a href= ...) removed.
• autoLinkUrls
• string $text
• array $htmlOptions
Returns $text with URLs wrapped in corresponding &lt;a&gt; tags.
• autoLinkEmails
• string $text
• array $htmlOptions
Returns $text with email addresses wrapped in corresponding &lt;a&gt; tags.
• autoLink
• string $text
• array $htmlOptions
Returns $text with URLs and emails wrapped in corresponding &lt;a&gt; tags.
• truncate
• string $text
• int $length
• string $ending = '...'
Returns the first $length number of characters of $text followed by $ending ('...' by default).
• excerpt
• string $text
• string $phrase
• int $radius = 100
• string $ending = '...'
Extracts an excerpt from the $text, grabbing the $phrase with a number of characters on each
side determined by $radius.
• flay
• string $text
• boolean $allowHtml = false
Text-to-html parser, similar to Textile or RedCloth, only with a little different syntax.

Time
The Time Helper provides methods that a developer may need for outputting Unix timestamps
and/or datetime strings into more understandable phrases to the browser.
Dates can be provided to all functions as either valid PHP datetime strings or Unix timestamps.
• fromString
• string $dateString
Returns a UNIX timestamp, given either a UNIX timestamp or a valid strtotime() date string.
• nice
• string $dateString
• boolean $return = false
Returns a nicely formatted date string. Dates are formatted as "D, M jS Y, H:i", or 'Mon, Jan 1st
2005, 12:00'.
• niceShort
• string $dateString
• boolean $return = false
Formats date strings as specified in nice(), but ouputs "Today, 12:00" if the date string is today,
or "Yesterday, 12:00" if the date string was yesterday.
• isToday
• string $dateString
Returns true if given datetime string is today.
• daysAsSql
• string $begin
• string $end
• string $fieldName
• boolean $return = false
Returns a partial SQL string to search for all records between two dates.
• dayAsSql
• string $dateString
• string $fieldName
• boolean $return = false
Returns a partial SQL string to search for all records between two times occurring on the same
day.
• isThisYear
• string $dateString
• boolean $return = false
Returns true if given datetime string is within current year.
• wasYesterday
• string $dateString
• boolean $return = false
Returns true if given datetime string was yesterday.
• isTomorrow
• string $dateString
• boolean $return = false
Returns true if given datetime string is tomorrow.
• toUnix
• string $dateString
• boolean $return = false
Returns a UNIX timestamp from a textual datetime description. Wrapper for PHP function
strtotime().
• toAtom
• string $dateString
• boolean $return = false
Returns a date formatted for Atom RSS feeds.
• toRSS
• string $dateString
• boolean $return = false
Formats date for RSS feeds
• timeAgoInWords
• string $dateString
• boolean $return = false
Returns either a relative date or a formatted date depending on the difference between the current
time and given datetime. $datetime should be in a strtotime-parsable format like MySQL
datetime.
• relativeTime
• string $dateString
• boolean $return = false
Works much like timeAgoInWords(), but includes the ability to create output for timestamps in
the future as well (i.e. "Yesterday, 10:33", "Today, 9:42", and also "Tomorrow, 4:34").
• wasWithinLast
• string $timeInterval
• string $dateString
• boolean $return = false
Returns true if specified datetime was within the interval specified, else false. The time interval
should be specifed with the number as well as the units: '6 hours', '2 days', etc.

Creating Your Own Helpers


Have the need for some help with your view code? If you find yourself needing a specific bit of
view logic over and over, you can make your own view helper.
Extending the Cake Helper Class
Let's say we wanted to create a helper that could be used to output a CSS styled link you needed
in your application. In order to fit your logic in to Cake's existing Helper structure, you'll need to
create a new class in /app/views/helpers. Let's call our helper LinkHelper. The actual php class
file would look something like this:
/app/views/helpers/link.php
Plain Text View

class LinkHelper extends Helper


{
function makeEdit($title, $url)
{
// Logic to create specially formatted link goes here...
}
}
1. class LinkHelper extends Helper
2. {
3. function makeEdit($title, $url)
4. {
5. // Logic to create specially formatted link goes here...
6. }
7. }
There are a few functions included in Cake's helper class you might want to take advantage of:
• output
• string $string
• boolean $return = false
Decides whether to output or return a string based on AUTO_OUTPUT (see
/app/config/core.php) and $return's value. You should use this function to hand any data back to
your view.
• loadConfig
Returns your application's current core configuration and tag definitions.
Let's use output() to format our link title and URL and hand it back to the view.
/app/views/helpers/link.php (logic added)
Plain Text View

class LinkHelper extends Helper


{
function makeEdit($title, $url)
{
// Use the helper's output function to hand formatted
// data back to the view:

return $this->output("<div class=\"editOuter\"><a href=\"$url\"


class=\"edit\">$title</a></div>");
}
}
1. class LinkHelper extends Helper
2. {
3. function makeEdit($title, $url)
4. {
5. // Use the helper's output function to hand formatted
6. // data back to the view:
7. return $this->output("<div class=\"editOuter\"><a href=\"$url\"
class=\"edit\">$title</a></div>");
8. }
9. }
Including other Helpers
You may wish to use some functionality already existing in another helper. To take advantage of
that, you can specify helpers you wish to use with a $helpers array, formatted just as you would
in a controller.
/app/views/helpers/link.php (using other helpers)
Plain Text View

class LinkHelper extends Helper


{

var $helpers = array('Html');

function makeEdit($title, $url)


{
// Use the HTML helper to output
// formatted data:

$link = $this->Html->link($title, $url, array('class' => 'edit'));

return $this->output("<div class=\"editOuter\">$link</div>");


}
}
1. class LinkHelper extends Helper
2. {
3. var $helpers = array('Html');
4. function makeEdit($title, $url)
5. {
6. // Use the HTML helper to output
7. // formatted data:
8. $link = $this->Html->link($title, $url, array('class' => 'edit'));
9. return $this->output("<div class=\"editOuter\">$link</div>");
10. }
11. }
Using your Custom Helper
Once you've created your helper and placed it in /app/views/helpers/, you'll be able to include it
in your controllers using the special variable $helpers.
Plain Text View

class ThingsController
{
var $helpers = array('Html', 'Link');
}
1. class ThingsController
2. {
3. var $helpers = array('Html', 'Link');
4. }
Remember to include the HTML helper in the array if you plan to use it elsewhere. The naming
conventions are similar to that of models.
1. LinkHelper = class name
2. link = key in helpers array
3. link.php = name of php file in /app/views/helpers.
« Components | Cake's Global Constants And Functions »

12 Cake's Global Constants And Functions


• Edit
• Comments (0)
• History
Here are some globally available constants and functions that you might find useful as you build
your application with Cake.

Global Functions
Here are Cake's globally available functions. Many of them are convenience wrappers for long-
named PHP functions, but some of them (like vendor() and uses()) can be used to include code,
or perform other useful functions. Chances are if you're wanting a nice little function to do
something annoying over and over, it's here.
• config
Loads Cake's core configuration file. Returns true on success.
• uses
• string $lib1
• string $lib2...
Used to load Cake's core libaries (found in cake/libs/). Supply the name of the lib filename
without the '.php' extension.
Plain Text View

uses('sanitize', 'security');
1. uses('sanitize', 'security');
• vendor
• string $lib1
• string $lib2...
Used to load external libraries found in the /vendors directory. Supply the name of the lib
filename without the '.php' extension.
Plain Text View

vendor('myWebService', 'nusoap');
1. vendor('myWebService', 'nusoap');
• debug
• mixed $var
• boolean $showHtml = false
If the application's DEBUG level is non-zero, the $var is printed out. If $showHTML is true, the
data is rendered to be browser-friendly.
• a
Returns an array of the parameters used to call the wrapping function.
Plain Text View

<function someFunction()
{
echo print_r(a('foo', 'bar'));
}

someFunction();

// output:

array(
[0] => 'foo',
[1] => 'bar'
)
1. <function someFunction()
2. {
3. echo print_r(a('foo', 'bar'));
4. }
5. someFunction();
6. // output:
7. array(
8. [0] => 'foo',
9. [1] => 'bar'
10. )
• aa
Used to create associative arrays formed from the parameters used to call the wrapping function.
Plain Text View

echo aa('a','b'); // output: array( 'a' => 'b' )


1. echo aa('a','b'); // output: array( 'a' => 'b' )
• e
• string $text
Convenience wrapper for echo().
• low
Convenience wrapper for strtolower().
• up
Convenience wrapper for strtoupper().
• r
• string $search
• string $replace
• string $subject
Convenience wrapper for str_replace().
• pr
• mixed $data
Convenience function equivalent to:
echo "<pre>" . print_r($data) . "</pre>";

Only prints out information if DEBUG is non-zero.


• am
• array $array1
• array $array2...
Merges and returns the arrays supplied in the parameters.
• env
• string $key
Gets an environment variable from available sources. Used as a backup if $_SERVER or $_ENV
are disabled.
This function also emulates PHP_SELF and DOCUMENT_ROOT on unsupporting servers. In
fact, it's a good idea to always use env() instead of $_SERVER or getenv() (especially if you
plan to distribute the code), since it's a full emulation wrapper.
• cache
• string $path
• string $expires
• string $target = 'cache'
Writes the data in $data to the path in /app/tmp specified by $path as a cache. The expiration
time specified by $expires must be a valid strtotime() string. The $target of the cached data can
either be 'cache' or 'public'.
• clearCache
• string $search
• string $path = 'views'
• string $ext
Used to delete files in the cache directories, or clear contents of cache directories.
If $search is a string, matching cache directory or file names will be removed from the cache.
The $search parameter can also be passed as an array of names of files/directories to be cleared.
If empty, all files in /app/tmp/cache/views will be cleared.
The $path parameter can be used to specify which directory inside of /tmp/cache is to be cleared.
Defaults to 'views'.
The $ext param is used to specify files with a certain file extention you wish to clear.
• stripslashes_deep
• array $array
Recursively strips slashes from all values in an array.
• countdim
• array $array
Returns the number of dimensions in the supplied array.
• fileExistsInPath
• string $file
Searches the current include path for a given filename. Returns the path to that file if found, false
if not found.
• convertSlash
• string $string
Converts forward slashes to underscores and removes first and last underscores in a string.

CakePHP Core Definition Constants


ACL_CLASSNAME the name of the class currently performing and managing ACL
for CakePHP. This constant is in place to allow for users to
integrate third party classes.

the name of the file where the class ACL_CLASSNAME can be


ACL_FILENAME
found inside of.

if set to false, session_start() is not automatically called during


AUTO_SESSION
requests to the application.

if set to false, view caching is turned off for the entire


CACHE_CHECK
application

determines the level of session security for the application in accordance


with CAKE_SESSION_TIMEOUT. Can be set to 'low', 'medium', or
'high'. Depending on the setting, CAKE_SESSION_TIMEOUT is
CAKE_SECURITY multiplied according to the following:
1. low: 300
2. medium: 100
3. high: 10
CAKE_SESSION_COO
the name of session cookie for the application.
KIE

set to 'php', 'file', or 'database'.


1. php: Cake uses PHP's default session handling (usually defined in
CAKE_SESSION_SAV php.ini)
E
2. file: Session data is stored and managed in /tmp
3. database: Cake's database session handling is used (see Chapter
"The Cake Session Component" for more details).
CAKE_SESSION_STRI
a random string used in session mangement
NG

the name of the table for storing session data (if


CAKE_SESSION_TABL CAKE_SESSION_SAVE == 'database'). Do not include a prefix
E here if one has already been specified for the default database
connection.

CAKE_SESSION_TIME number of seconds until session timeout. This figure is


OUT multiplied by CAKE_SECURITY.

if set to true, CSS style sheets are compressed on output. This


requires a /var/cache directory writable by the webserver. To
COMPRESS_CSS
use, reference your style sheets using /ccss (rather than /css)
or use Controller::cssTag().
defines the level of error reporting and debug output the CakePHP
application will render. Can be set to an integer from 0 to 3.
1. 0: Production mode. No error output, no debug messages shown.
DEBUG 2. 1: Development mode. Warnings and errors shown, along with
debug messages.
3. 2: Same as in 1, but with SQL output.
4. 3: Same as in 2, but with full dump of current object (usually the
Controller).
Error constant. Used for differentiating error logging and
LOG_ERROR
debugging. Currently PHP supports LOG_DEBUG.

MAX_MD5SIZE The maximum size (in bytes) to perform an md5() hash upon.

If set to true, Cake's bulit in webservices functionality is turned


WEBSERVICES
on.

CakePHP Path Constants


APP the path to the application's directory.

APP_DIR the name of the current application's app directory.

APP_PATH absolute path to the application's app directory.

CACHE path to the cache files directory.

CAKE path to the application's cake directory.

COMPONENTS path to the application's components directory.

CONFIGS path to the configuration files directory.

CONTROLLER_T
path to the controller tests directory.
ESTS

CONTROLLERS path to the application's controllers.

CSS path to the CSS files directory.

ELEMENTS path to the elements directory.

HELPER_TESTS path to the helper tests directory.

HELPERS path to the helpers directory.

path to the inflections directory (usually inside the configuration


INFLECTIONS
directory).
JS path to the JavaScript files directory.

LAYOUTS path to the layouts directory.

LIB_TESTS path to the Cake Library tests directory.

LIBS path to the Cake libs directory.

LOGS path to the logs directory.

MODEL_TESTS path to the model tests directory.

MODELS path to the models directory.

SCRIPTS path to the Cake scripts directory.

path to the tests directory (parent for the models, controllers, etc.
TESTS
test directories)

TMP path to the tmp directory.

VENDORS path to the vendors directory.

VIEWS path to the views directory.

CakePHP Webroot Configuration Paths


CORE_PATH path to the Cake core libraries.

WWW_ROOT path to the application's webroot directory

CAKE_CORE_INCLUDE_
path to the Cake core libraries.
PATH

the name of the directory parent to the base index.php


ROOT
of CakePHP.

WEBROOT_DIR the name of the application's webroot directory.

« Helpers | Data Validation »

13 Data Validation
• Edit
• Comments (1)
• History
Creating custom validation rules can help to make sure the data in a Model conforms to the
business rules of the application, such as passwords can only be eight characters long, user
names can only have letters, etc.
The first step to data validation is creating the validation rules in the Model. To do that, use the
Model::validate array in the Model definition, for example:
/app/models/user.php
Plain Text View

<?php
class User extends AppModel
{
var $name = 'User';

var $validate = array(


'login' => '/[a-z0-9\_\-]{3,}$/i',
'password' => VALID_NOT_EMPTY,
'email' => VALID_EMAIL,
'born' => VALID_NUMBER
);
}
?>
1. <?php
2. class User extends AppModel
3. {
4. var $name = 'User';
5. var $validate = array(
6. 'login' => '/[a-z0-9\_\-]{3,}$/i',
7. 'password' => VALID_NOT_EMPTY,
8. 'email' => VALID_EMAIL,
9. 'born' => VALID_NUMBER
10. );
11. }
12. ?>
Validations are defined using Perl-compatibile regular expressions, some of which are pre-
defined in /libs/validators.php. These are:
• VALID_NOT_EMPTY
• VALID_NUMBER
• VALID_EMAIL
• VALID_YEAR
If there are any validations present in the model definition (i.e. in the $validate array), they will
be parsed and checked during saves (i.e. in the Model::save() method). To validate the data
directly use the Model::validates() (returns false if data is incorrect) and Model::invalidFields()
(which returns an array of error messages).
But usually the data is implicit in the controller code. The following example demonstrates how
to create a form-handling action:
Form-handling Action in /app/controllers/blog_controller.php
Plain Text View

<?php
class BlogController extends AppController {

var $uses = array('Post');

function add ()
{
if (empty($this->data))
{
$this->render();
}
else
{
if($this->Post->save($this->data))
{
//ok cool, the stuff is valid
}
else
{
//Danger, Will Robinson. Validation errors.
$this->set('errorMessage', 'Please correct errors below.');
$this->render();
}
}
}
}
?>
1. <?php
2. class BlogController extends AppController {
3. var $uses = array('Post');
4. function add ()
5. {
6. if (empty($this->data))
7. {
8. $this->render();
9. }
10. else
11. {
12. if($this->Post->save($this->data))
13. {
14. //ok cool, the stuff is valid
15. }
16. else
17. {
18. //Danger, Will Robinson. Validation errors.
19. $this->set('errorMessage', 'Please correct errors below.');
20. $this->render();
21. }
22. }
23. }
24. }
25. ?>
The view used by this action can look like this:
The add form view in /app/views/blog/add.thtml
Plain Text View

<h2>Add post to blog</h2>


<form action="<?php echo $html->url('/blog/add')?>" method="post">
<div class="blog_add">
<p>Title:
<?php echo $html->input('Post/title', array('size'=>'40'))?>
<?php echo $html->tagErrorMsg('Post/title', 'Title is
required.')?>
</p>
<p>Body
<?php echo $html->textarea('Post/body') ?>
<?php echo $html->tagErrorMsg('Post/body', 'Body is required.')?>
</p>
<p><?=$html->submit('Save')?></p>
</div>
</form>
1. <h2>Add post to blog</h2>
2. <form action="<?php echo $html->url('/blog/add')?>" method="post">
3. <div class="blog_add">
4. <p>Title:
5. <?php echo $html->input('Post/title', array('size'=>'40'))?>
6. <?php echo $html->tagErrorMsg('Post/title', 'Title is required.')?>
7. </p>
8. <p>Body
9. <?php echo $html->textarea('Post/body') ?>
10. <?php echo $html->tagErrorMsg('Post/body', 'Body is required.')?>
11. </p>
12. <p><?=$html->submit('Save')?></p>
13. </div>
14. </form>
The Controller::validates($model[, $model...]) is used to check any custom validation added in
the model. The Controller::validationErrors() method returns any error messages thrown in the
model so they can be displayed by tagErrorMsg() in the view.
If you'd like to perform some custom validation apart from the regex based Cake validation, you
can use the invalidate() function of your model to flag a field as erroneous. Imagine that you
wanted to show an error on a form when a user tries to create a username that already exists in
the system. Because you can't just ask Cake to find that out using regex, you'll need to do your
own validation, and flag the field as invalid to invoke Cake's normal form invalidation process.
Remember to use a field name that isn't already in the model, in order to avoid any conflicts.
The controller might look something like this:
Plain Text View

<?php

class UsersController extends AppController


{
function create()
{
// Check to see if form data has been submitted
if (!empty($this->data['User']))
{
//See if a user with that username exists
$user = $this->User->findByUsername($this->data['User']
['username']);

// Invalidate the field to trigger the HTML Helper's error


messages
if (!empty($user['User']['username']))
{
$this->User->invalidate('username_unique');//populates
tagErrorMsg('User/username_unique')
}

//Try to save as normal, shouldn't work if the field was


invalidated.
if($this->User->save($this->data))
{
$this->redirect('/users/index/saved');
}
else
{
$this->render();
}
}
}
}

?>
1. <?php
2. class UsersController extends AppController
3. {
4. function create()
5. {
6. // Check to see if form data has been submitted
7. if (!empty($this->data['User']))
8. {
9. //See if a user with that username exists
10. $user = $this->User->findByUsername($this->data['User']['username']);
11. // Invalidate the field to trigger the HTML Helper's error messages
12. if (!empty($user['User']['username']))
13. {
14. $this->User->invalidate('username_unique');//populates
tagErrorMsg('User/username_unique')
15. }
16. //Try to save as normal, shouldn't work if the field was invalidated.
17. if($this->User->save($this->data))
18. {
19. $this->redirect('/users/index/saved');
20. }
21. else
22. {
23. $this->render();
24. }
25. }
26. }
27. }
28. ?>
If you want to invalidate a piece of data that is outside of the Model itself, be sure to add that
data to the Model using the set() method. This informs the model about that data so it can be
handled properly.
« Cake's Global Constants And Functions | Plugins »
14 Plugins
• Edit
• Comments (0)
• History
CakePHP allows you to set up a combination of controllers, models, and views and release them
as a packaged application plugin that others can use in their CakePHP applications. Have a sweet
user management module, simple blog, or web services module in one of your applications?
Package it as a CakePHP plugin so you can pop it into other applications.
The main tie between a plugin and the application it has been installed into is the application's
configuration (database connection, etc.). Otherwise, it operates in its own little space, behaving
much like it would if it were an application on it's own.

Creating a Plugin
As a working example, let's create a new plugin that orders pizza for you. What could be more
useful in any CakePHP application? To start out, we'll need to place our plugin files inside the
/app/plugins folder. The name of the parent folder for all the plugin files is important, and will
be used in many places, so pick wisely. For this plugin, let's use the name 'pizza'. This is how the
setup will eventually look:
Pizza Ordering Filesystem Layout
Plain Text View

/app
/plugins
/pizza
/controllers <- plugin controllers go here
/models <- plugin models go here
/views <- plugin views go here
/pizza_app_controller.php <- plugin's AppController, named
after the plugin
/pizza_app_model.php <- plugin's AppModel, named after the
plugin
1. /app
2. /plugins
3. /pizza
4. /controllers <- plugin controllers go here
5. /models <- plugin models go here
6. /views <- plugin views go here
7. /pizza_app_controller.php <- plugin's AppController, named after the
plugin
8. /pizza_app_model.php <- plugin's AppModel, named after the plugin
While defining an AppController and AppModel for any normal application is not required,
defining them for plugins is. You'll need to create them before your plugin works. These two
special classes are named after the plugin, and extend the parent application's AppController and
AppModel. Here's what they should look like:
Pizza Plugin AppController: /app/plugins/pizza/pizza_app_controller.php
Plain Text View

<?php

class PizzaAppController extends AppController


{
//...
}

?>
1. <?php
2. class PizzaAppController extends AppController
3. {
4. //...
5. }
6. ?>
Pizza Plugin AppModel: /app/plugins/pizza/pizza_app_model.php
Plain Text View

<?php

class PizzaAppModel extends AppModel


{
//...
}

?>
1. <?php
2. class PizzaAppModel extends AppModel
3. {
4. //...
5. }
6. ?>
If you forget to define these special classes, CakePHP will hand you "Missing Controller" errors
until the problem is rectified.

Plugin Controllers
Controllers for our pizza plugin will be stored in /app/plugins/pizza/controllers. Since the main
thing we'll be tracking is pizza orders, we'll need an OrdersController for this plugin.
While it isn't required, it is recommended that you name your plugin controllers something
relatively unique in order to avoid namespace conflicts with parent applications. Its not a stretch
to think that a parent application might have a UsersController, OrdersController, or
ProductsController: so you might want to be creative with controller names, or prepend the name
of the plugin to the classname (PizzaOrdersController, in this case).
So, we place our new PizzaOrdersController in /app/plugins/pizza/controllers and it looks like
so:
/app/plugins/pizza/controllers/pizza_orders_controller.php
Plain Text View

<?php

class PizzaOrdersController extends PizzaAppController


{
var $name = 'PizzaOrders';

function index()
{
//...
}

function placeOrder()
{
//...
}
}

?>
1. <?php
2. class PizzaOrdersController extends PizzaAppController
3. {
4. var $name = 'PizzaOrders';
5. function index()
6. {
7. //...
8. }
9. function placeOrder()
10. {
11. //...
12. }
13. }
14. ?>
Note how this controller extends the plugin's AppController (called PizzaAppController) rather
than just the parent application's AppController.
Plugin Models
Models for the plugin are stored in /app/plugins/pizza/models. We've already defined a
PizzaOrdersController for this plugin, so let's create the model for that controller, called
PizzaOrders (the classname PizzaOrders is consistent with our naming scheme, and is unique
enough, so we'll leave it as is).
/app/plugins/pizza/models/pizza_order.php
Plain Text View

<?php

class PizzaOrder extends PizzaAppModel


{
var $name = 'PizzaOrder';
}

?>
1. <?php
2. class PizzaOrder extends PizzaAppModel
3. {
4. var $name = 'PizzaOrder';
5. }
6. ?>
Again, note that this class extends PizzaAppModel rather than AppModel.

Plugin Views
Views behave exactly as they do in normal applications. Just place them in the right folder inside
of the /app/plugins/[plugin]/views folder. For our pizza ordering plugin, we'll need at least one
view for our PizzaOrdersController::index() action, so let's include that as well:
/app/plugins/pizza/views/pizza_orders/index.thtml
Plain Text View

<h1>Order A Pizza</h1>
<p>Nothing goes better with Cake than a good pizza!</p>
<!-- An order form of some sort might go here....-->
1. <h1>Order A Pizza</h1>
2. <p>Nothing goes better with Cake than a good pizza!</p>
3. <!-- An order form of some sort might go here....-->

Working With Plugins


So, now that you've built evertything, it should be ready to distribute (though we'd suggest you
also distribute a few extras like a readme, sql file, etc.).
Once a plugin as been installed in /app/plugins, you can access it at the URL
/pluginname/controllername/action. In our pizza ordering plugin example, we'd access our
PizzaOrdersController at /pizza/pizzaOrders.
Some final tips on working with plugins in your CakePHP applications:
1. When you don't have a [Plugin]AppController and [Plugin]AppModel, you'll get missing
Controller errors when trying to access a plugin controller.
2. You can have a default controller with the name of your plugin. If you do that, you can
access it via /[plugin]/action. For example, a plugin named 'users' with a controller named
UsersController can be accessed at /users/add if there is no plugin called AddController
in your [plugin]/controllers folder.
3. Plugins will use the layouts from the /app/views/layouts folder by default.
4. You can do inter-plugin communication by using requestAction in your controllers.
$this->requestAction('/plugin/controller/action');
5. If you use requestAction, make sure controller and model names are as unique as
possible. Otherwise you might get PHP "redefined class ..." errors.
Many thanks to Felix Geisendorfer (the_undefined) for the initial material for this chapter.
« Data Validation | Access Control Lists »

15 Access Control Lists


• Edit
• Comments (1)
• History
Understanding How ACL Works
Most important, powerful things require some sort of access control. Access control lists are a
way to manage application permissions in a fine-grained, yet easily maintainable and
manageable way. Access control lists, or ACL, handle two main things: things that want stuff,
and things that are wanted. In ACL lingo, things (most often users) that want to use stuff are
called access request objects, or AROs. Things in the system that are wanted (most often actions
or data) are called access control objects, or ACOs. The entities are called 'objects' because
sometimes the requesting object isn't a person - sometimes you might want to limit the access
certain Cake controllers have to initiate logic in other parts of your application. ACOs could be
anything you want to control, from a controller action, to a web service, to a line on your
grandma's online diary.
To use all the acronyms at once: ACL is what is used to decide when an ARO can have access to
an ACO.
Now, in order to help you understand this, let's use a practial example. Imagine, for a moment, a
computer system used by a group of adventurers. The leader of the group wants to forge ahead
on their quest while maintaining a healthy amount of privacy and security for the other members
of the party. The AROs involved are as following:
• Gandalf
• Aragorn
• Bilbo
• Frodo
• Gollum
• Legolas
• Gimli
• Pippin
• Merry
These are the entities in the system that will be requesting things (the ACOs) from the system. It
should be noted that ACL is *not* a system that is meant to authenticate users. You should
already have a way to store user information and be able to verify that user's identity when they
enter the system. Once you know who a user is, that's where ACL really shines. Okay - back to
our adventure.
The next thing Gandalf needs to do is make an initial list of things, or ACOs, the system will
handle. His list might look something like:
• Weapons
• The One Ring
• Salted Pork
• Diplomacy
• Ale
Traditionally, systems were managed using a sort of matrix, that showed a basic set of users and
permissions relating to objects. If this information were stored in a table, it might look like the
following, with X's indicating denied access, and O's indicating allowed access.
Weapo The One Salted Diploma
Ale
ns Ring Pork cy

Ganda Ye
No No Yes Yes
lf s

Aragor Ye
Yes No Yes Yes
n s

Ye
Bilbo No No No No
s

Ye
Frodo No Yes No No
s

Gollu
No No Yes No No
m

Legola Yes No Yes Yes Ye


s s

Gimli Yes No Yes No No

Ye
Pippin No No No Yes
s

Ye
Merry No No No No
s

At first glance, it seems that this sort of system could work rather well. Assignments can be
made to protect security (only Frodo can access the ring) and protect against accidents (keeping
the hobbits out of the salted pork). It seems fine grained enough, and easy enough to read, right?
For a small system like this, maybe a matrix setup would work. But for a growing system, or a
system with a large amount of resources (ACOs) and users (AROs), a table can become
unwieldy rather quickly. Imagine trying to control access to the hundreds of war encampments
and trying to manage them by unit, for example. Another drawback to matrices is that you can't
really logically group sections of users, or make cascading permissions changes to groups of
users based on those logical groupings. For example, it would sure be nice to automatically allow
the hobbits access to the ale and pork once the battle is over: Doing it on an indivudual user basis
would be tedious and error prone, while making a cascading permissions change to all 'hobbits'
would be easy.
ACL is most usually implemented in a tree structure. There is usually a tree of AROs and a tree
of ACOs. By organizing your objects in trees, permissions can still be dealt out in a granular
fashion, while still maintaining a good grip on the big picture. Being the wise leader he is,
Gandalf elects to use ACL in his new system, and organizes his objects along the following
lines:
Fellowship of the Ring:
• Warriors
○ Aragorn
○ Legolas
○ Gimli
• Wizards
○ Gandalf
• Hobbits
○ Frodo
○ Bilbo
○ Merry
○ Pippin
• Vistors
○ Gollum
By structuring our party this way, we can define access controls to the tree, and apply those
permissions to any children. The default permission is to deny access to everything. As you work
your way down the tree, you pick up permissions and apply them. The last permission applied
(that applies to the ACO you're wondering about) is the one you keep. So, using our ARO tree,
Gandalf can hang on a few permissions:
Fellowship of the Ring: [Deny: ALL]
• Warriors [Allow: Weapons, Ale, Elven Rations, Salted Pork]
○ Aragorn
○ Legolas
○ Gimli
• Wizards [Allow: Salted Pork, Diplomacy, Ale]
○ Gandalf
• Hobbits [Allow: Ale]
○ Frodo
○ Bilbo
○ Merry
○ Pippin
• Vistors [Allow: Salted Pork]
○ Gollum
If we wanted to use ACL to see if the Pippin was allowed to access the ale, we'd first get his path
in the tree, which is Fellowship->Hobbits->Pippin. Then we see the different permissions that
reside at each of those points, and use the most specific permission relating to Pippin and the
Ale.
1. Fellowship = DENY Ale, so deny (because it is set to deny all ACOs)
2. Hobbits = ALLOW Ale, so allow
3. Pippin = ?; There really isn't any ale-specific information so we stick with ALLOW.
4. Final Result: allow the ale.
The tree also allows us to make finer adjustments for more granular control - while still keeping
the ability to make sweeping changes to groups of AROs:
• Warriors [Allow: Weapons, Ale, Elven Rations, Salted Pork]
○ Aragorn [Allow: Diplomacy]
○ Legolas
○ Gimli
• Wizards [Allow: Salted Pork, Diplomacy, Ale]
○ Gandalf
• Hobbits [Allow: Ale]
○ Frodo [Allow: Ring]
○ Bilbo
○ Merry [Deny: Ale]
○ Pippin [Allow: Diplomacy]
• Vistors [Allow: Salted Pork]
○ Gollum
You can see this because the Aragorn ARO maintains is permissions just like others in the
Warriors ARO group, but you can still make fine-tuned adjustments and special cases when you
see fit. Again, permissions default to DENY, and only change as the traversal down the tree
forces an ALLOW. To see if Merry can access the Ale, we'd find his path in the tree: Fellowship-
>Hobbits->Merry and work our way down, keeping track of ale-related permissions:
1. Fellowship = DENY (because it is set to deny all), so deny the ale.
2. Hobbits = ALLOW: ale, so allow the ale
3. Merry = DENY ale, so deny the ale
4. Final Result: deny the ale.

Defining Permissions: Cake's INI-based ACL


Cake's first ACL implementation was based off of INI files stored in the Cake installation. While
its useful and stable, we recommend that you use the database backed ACL solution, mostly
because of its ability to create new ACOs and AROs on the fly. We meant it for usage in simple
applications - and especially for those folks who might not be using a database for some reason.
By default, CakePHP's ACL is database-driven. To enable INI-based ACL, set
ACL_CLASSNAME to INI_ACL, and ACL_FILENAME to ini_acl in core.php.
ARO/ACO permissions are specified in /app/config/acl.ini.php. Instructions on specifying
access can be found at the beginning of acl.ini.php:
Plain Text View

; acl.ini.php - Cake ACL Configuration


; ---------------------------------------------------------------------
; Use this file to specify user permissions.
; aco = access control object (something in your application)
; aro = access request object (something requesting access)
;
; User records are added as follows:
;
; [uid]
; groups = group1, group2, group3
; allow = aco1, aco2, aco3
; deny = aco4, aco5, aco6
;
; Group records are added in a similar manner:
;
; [gid]
; allow = aco1, aco2, aco3
; deny = aco4, aco5, aco6
;
; The allow, deny, and groups sections are all optional.
; NOTE: groups names *cannot* ever be the same as usernames!
1. ; acl.ini.php - Cake ACL Configuration
2. ; ---------------------------------------------------------------------
3. ; Use this file to specify user permissions.
4. ; aco = access control object (something in your application)
5. ; aro = access request object (something requesting access)
6. ;
7. ; User records are added as follows:
8. ;
9. ; [uid]
10. ; groups = group1, group2, group3
11. ; allow = aco1, aco2, aco3
12. ; deny = aco4, aco5, aco6
13. ;
14. ; Group records are added in a similar manner:
15. ;
16. ; [gid]
17. ; allow = aco1, aco2, aco3
18. ; deny = aco4, aco5, aco6
19. ;
20. ; The allow, deny, and groups sections are all optional.
21. ; NOTE: groups names *cannot* ever be the same as usernames!
Using the INI file, you can specify users (AROs), the group(s) they belong to, and their own
personal permissions. You can also specify groups along with their permissions. To learn how to
use Cake's ACL component to check permissions using this INI file, see section 11.4.

Defining Permissions: Cake's Database ACL


Getting Started
The default ACL permissions implementation is database stored. Database ACL, or dbACL
consists of a set of core models, and a command-line script that comes with your Cake
installation. The models are used by Cake to interact with your database in order to store and
retrieve nodes the ACL trees. The command-line script is used to help you get started and be able
to interact with your trees.
To get started, first you'll need to make sure your /app/config/database.php is present and
correctly configured. For a new Cake installation, the easiest way to tell that this is so is to bring
up the installation directory using a web browser. Near the top of the page, you should see the
messages "Your database configuration file is present." and "Cake is able to connect to the
database." if you've done it correctly. See section 4.1 for more information on database
configuration.
Next, use the the ACL command-line script to initialize your database to store ACL information.
The script found at /cake/scripts/acl.php will help you accomplish this. Initialize the your
database for ACL by executing the following command (from your /cake/scripts/ directory):
Initializing your database using acl.php
Plain Text View

$ php acl.php initdb

Initializing Database...
Creating access control objects table (acos)...
Creating access request objects table (aros)...
Creating relationships table (aros_acos)...

Done.
1. $ php acl.php initdb
2. Initializing Database...
3. Creating access control objects table (acos)...
4. Creating access request objects table (aros)...
5. Creating relationships table (aros_acos)...
6. Done.
At this point, you should be able to check your project's database to see the new tables. If you're
curious about how Cake stores tree information in these tables, read up on modified database tree
traversal. Basically, it stores nodes, and their place in the tree. The acos and aros tables store the
nodes for their respective trees, and the aros_acos table is used to link your AROs to the ACOs
they can access.
Now, you should be able to start creating your ARO and ACO trees.
Creating Access Request Objects (AROs) and Access Control Objects (ACOs)
There are two ways of referring to AROs/ACOs. One is by giving them an numeric id, which is
usually just the primary key of the table they belong to. The other way is by giving them a string
alias. The two are not mutually exclusive.
The way to create a new ARO is by using the methods defined the the Aro Cake model. The
create() method of the Aro class takes three parameters: $link_id, $parent_id, and $alias. This
method creates a new ACL object under the parent specified by a parent_id - or as a root object
if the $parent_id passed is null. The $link_id allows you to link a current user object to Cake's
ACL structures. The alias parameter allows you address your object using a non-integer ID.
Before we can create our ACOs and AROs, we'll need to load up those classes. The easiest way
to do this is to include Cake's ACL Component in your controller using the $components array:
Plain Text View

var $components = array('Acl');


1. var $components = array('Acl');
Once we've got that done, let's see what some examples of creating these objects might look like.
The following code could be placed in a controller action somewhere:
Plain Text View

$aro = new Aro();


1. $aro = new Aro();
First, set up a few AROs. These objects will have no parent initially.
Plain Text View

$aro->create( 1, null, 'Bob Marley' );<br />


$aro->create( 2, null, 'Jimi Hendrix');<br />
$aro->create( 3, null, 'George Washington');<br />
$aro->create( 4, null, 'Abraham Lincoln');
1. $aro->create( 1, null, 'Bob Marley' );<br />
2. $aro->create( 2, null, 'Jimi Hendrix');<br />
3. $aro->create( 3, null, 'George Washington');<br />
4. $aro->create( 4, null, 'Abraham Lincoln');
Now, we can make groups to organize these users. Notice that the IDs for these objects are 0,
because they will never tie to users in our system.
Plain Text View

$aro->create(0, null, 'Presidents');<br />


$aro->create(0, null, 'Artists');
1. $aro->create(0, null, 'Presidents');<br />
2. $aro->create(0, null, 'Artists');
Now, hook AROs to their respective groups:
Plain Text View

$aro->setParent('Presidents', 'George Washington');<br />


$aro->setParent('Presidents', 'Abraham Lincoln');<br />
$aro->setParent('Artists', 'Jimi Hendrix');<br />
$aro->setParent('Artists', 'Bob Marley');
1. $aro->setParent('Presidents', 'George Washington');<br />
2. $aro->setParent('Presidents', 'Abraham Lincoln');<br />
3. $aro->setParent('Artists', 'Jimi Hendrix');<br />
4. $aro->setParent('Artists', 'Bob Marley');
In short, here is how to create an ARO:
Plain Text View

$aro = new Aro();


$aro->create($user_id, $parent_id, $alias);
1. $aro = new Aro();
2. $aro->create($user_id, $parent_id, $alias);
You can also create AROs using the command line script using
Plain Text View

$acl.php create aro <link_id> <parent_id> <alias>


1. $acl.php create aro <link_id> <parent_id> <alias>
Creating an ACO is done in a similar manner:
Plain Text View

$aco = new Aco();

//Create some access control objects:


$aco->create(1, null, 'Electric Guitar');
$aco->create(2, null, 'United States Army');
$aco->create(3, null, 'Fans');
1. $aco = new Aco();
2. //Create some access control objects:
3. $aco->create(1, null, 'Electric Guitar');
4. $aco->create(2, null, 'United States Army');
5. $aco->create(3, null, 'Fans');
We could create groups for these objects using setParent(), but we'll skip that
for this particular example. To create an ACO:
Plain Text View

$aco = new Aco();


$aco->create($id, $parent, $alias);
1. $aco = new Aco();
2. $aco->create($id, $parent, $alias);
The corresponding command line script command would be:
Plain Text View

$acl.php create aco <link_id> <parent_id> <alias>


1. $acl.php create aco <link_id> <parent_id> <alias>
Assigning Permissions
After creating our ACOs and AROs, we can finally assign permission between the two groups.
This is done using Cake's core Acl component. Let's continue on with our example:
Plain Text View

// First, in a controller, we'll need access


// to Cake's ACL component:

class SomethingsController extends AppController


{
// You might want to place this in the AppController
// instead, but here works great too.

var $components = array('Acl');


// Remember: ACL will always deny something
// it doesn't have information on. If any
// checks were made on anything, it would
// be denied. Let's allow an ARO access to an ACO.

function someAction()
{
//ALLOW

// Here is how you grant an ARO full access to an ACO


$this->Acl->allow('Jimi Hendrix', 'Electric Guitar');
$this->Acl->allow('Bob Marley', 'Electric Guitar');

// We can also assign permissions to groups, remember?


$this->Acl->Allow('Presidents', 'United States Army');

// The allow() method has a third parameter, $action.


// You can specify partial access using this parameter.
// $action can be set to create, read, update or delete.
// If no action is specified, full access is assumed.

// Look, don't touch, gentlemen:


$this->Acl->allow('George Washington', 'Electric Guitar', 'read');
$this->Acl->allow('Abraham Lincoln', 'Electric Guitar', 'read');

//DENY

//Denies work in the same manner:

//When his term is up...


$this->Acl->deny('Abraham Lincoln', 'United States Army');

}
}
1. // First, in a controller, we'll need access
2. // to Cake's ACL component:
3. class SomethingsController extends AppController
4. {
5. // You might want to place this in the AppController
6. // instead, but here works great too.
7. var $components = array('Acl');
8. // Remember: ACL will always deny something
9. // it doesn't have information on. If any
10. // checks were made on anything, it would
11. // be denied. Let's allow an ARO access to an ACO.
12. function someAction()
13. {
14. //ALLOW
15. // Here is how you grant an ARO full access to an ACO
16. $this->Acl->allow('Jimi Hendrix', 'Electric Guitar');
17. $this->Acl->allow('Bob Marley', 'Electric Guitar');
18. // We can also assign permissions to groups, remember?
19. $this->Acl->Allow('Presidents', 'United States Army');
20. // The allow() method has a third parameter, $action.
21. // You can specify partial access using this parameter.
22. // $action can be set to create, read, update or delete.
23. // If no action is specified, full access is assumed.
24. // Look, don't touch, gentlemen:
25. $this->Acl->allow('George Washington', 'Electric Guitar', 'read');
26. $this->Acl->allow('Abraham Lincoln', 'Electric Guitar', 'read');
27. //DENY
28. //Denies work in the same manner:
29. //When his term is up...
30. $this->Acl->deny('Abraham Lincoln', 'United States Army');
31. }
32. }
This particular controller isn't especially useful, but it is mostly meant to show you how the
process works. Using the Acl component in connection with your user management controller
would be the best usage. Once a user has been created on the system, her ARO could be created
and placed at the right point of the tree, and permissions could be assigned to specific ACO or
ACO groups based on her identity.
Permissions can also be assigned using the command line script packaged with Cake. The syntax
is similar to the model functions, and can be viewed by executing $php acl.php help.

Checking Permissions: The ACL Component


Checking permissions is the easiest part of using Cake's ACL: it consists of using a single
method in the Acl component: check(). A good way to implement ACL in your application might
be to place an action in your AppController that performs ACL checks. Once placed there, you
can access the Acl component and perform permissions checks application-wide. Here's an
example implementation:
Plain Text View

class AppController extends Controller


{
// Get our component
var $components = array('Acl');

function checkAccess($aco)
{
// Check access using the component:
$access = $this->Acl->check($this->Session->read('user_alias'), $aco,
$action = "*");

//access denied
if ($access === false)
{
echo "access denied";
exit;
}
//access allowed
else
{
echo "access allowed";
exit;
}
}
}
1. class AppController extends Controller
2. {
3. // Get our component
4. var $components = array('Acl');
5. function checkAccess($aco)
6. {
7. // Check access using the component:
8. $access = $this->Acl->check($this->Session->read('user_alias'), $aco,
$action = "*");
9. //access denied
10. if ($access === false)
11. {
12. echo "access denied";
13. exit;
14. }
15. //access allowed
16. else
17. {
18. echo "access allowed";
19. exit;
20. }
21. }
22. }
Basically, by making the Acl component available in the AppController, it will be visible for use
in any controller in your application. Here's the basic format:
Plain Text View

$this->Acl->Check($aro, $aco, $action = '*');


1. $this->Acl->Check($aro, $aco, $action = '*');
« Plugins | Data Sanitation: The Sanitize Class »

16 Data Sanitation: The Sanitize Class


• Edit
• Comments (1)
• History
Cake comes with Sanitize, a class you can use to rid user-submitted data of malicious attacks and
other unwanted data. Sanitize is a core library, so it can be used anywhere inside of your code,
but is probably best used in controllers or models.
Include the library and then create a new Sanitize object.
Plain Text View

uses('sanitize');
$mrClean = new Sanitize();
1. uses('sanitize');
2. $mrClean = new Sanitize();

Making Data Safe for use in SQL and HTML


This section explains how to use some of the functions that Sanitize offers.
• paranoid
• string $string
• array $allowedChars
This function strips anything out of the target $string that is not a plain-jane alphanumeric
character. You can, however, let it overlook certain characters by passing them along inside the
$allowedChars array.
Plain Text View

$badString = ";:<script><html>< // >@@#";

echo $mrClean->paranoid($badString);

// output: scripthtml
echo $mrClean->paranoid($badString, array(' ', '@'));

// output: scripthtml @@
1. $badString = ";:<script><html>< // >@@#";
2. echo $mrClean->paranoid($badString);
3. // output: scripthtml
4. echo $mrClean->paranoid($badString, array(' ', '@'));
5. // output: scripthtml @@
• html
• string $string
• boolean $remove = false
This method helps you get user submitted data ready for display inside an existing HTML layout.
This is especially useful if you don't want users to be able to break your layouts or insert images
or scripts inside of blog comments, forum posts, and the like. If the $remove option is set to true,
any HTML is removed rather than rendered as HTML entities.
Plain Text View

$badString = '<font size="99" color="#FF0000">HEY</font><script>...</script>';

echo $mrClean->html($badString);

// output: <font size="99" color="#FF0000">HEY</font><script>...</script>

echo $mrClean->html($badString, true);

// output: font size=99 color=#FF0000 HEY fontscript...script


1. $badString = '<font size="99"
color="#FF0000">HEY</font><script>...</script>';
2. echo $mrClean->html($badString);
3. // output: <font size="99"
color="#FF0000">HEY</font><script>...</script>
4. echo $mrClean->html($badString, true);
5. // output: font size=99 color=#FF0000 HEY fontscript...script
• sql
• string $string
Used to escape SQL statements by adding slashes, depending on the system's current
magic_quotes_gpc setting.
• cleanArray
• array @$dirtyArray
This function is an industrial strength, multi-purpose cleaner, meant to be used on entire arrays
(like $this->params['form'], for example). The function takes an array and cleans it: nothing is
returned because the array is passed by reference. The following cleaning operations are
performed on each element in the array (recursively):
1. Odd spaces (including 0xCA) are replaced with regular spaces.
2. HTML is replaced by its corresponding HTML entities (including \n to <br>).
3. Double-check special chars and remove carriage returns for increased SQL security.
4. Add slashes for SQL (just calls the sql function outlined above).
5. Swap user-inputted backslashes with trusted backslashes.
« Access Control Lists | The Cake Session Component »

17 The Cake Session Component


• Edit
• Comments (0)
• History
Cake comes preset to save session data in three ways: as temporary files inside of your Cake
installation, using the default PHP mechanism, or serialized in a database. By default, Cake uses
PHP's default settings. To override this in order to use temp files or a database, edit your core
configuration file at /app/config/core.php. Change the CAKE_SESSION_SAVE constant to
'cake', 'php', or 'database', depending on your application's needs.
core.php Session Configuration
Plain Text View

define('CAKE_SESSION_SAVE', 'php');
1. define('CAKE_SESSION_SAVE', 'php');
In order to use the database session storage, you'll need to create a table in your database. The
schema for that table can be found in /app/config/sql/sessions.sql.

Using the Cake Session Component


The Cake session component is used to interact with session information. It includes basic
session reading and writing, but also contains features for using sessions for error and reciept
messages (i.e. "Your data has been saved"). The Session Component is available in all Cake
controllers by default.
Here are some of the functions you'll use most:
• check
• string $name
Checks to see if the current key specified by $name has been set in the session.
• del
• string $name
• delete
• string $name
Deletes the session variable specified by $name.
• error
Returns the last error created by the CakeSession component. Mostly used for debugging.
• flash
• string $key = 'flash'
Returns the last message set in the session using setFlash(). If $key has been set, the message
returned is the most recent stored under that key.
• read
• string $name
Returns the session variable specified by $name.
• renew
Renews the currently active session by creating a new session ID, deleting the old one, and
passing the old session data to the new one.
• setFlash
• string $flashMessage
• string $layout = 'default'
• array $params
• string $key = 'flash'
Writes the message specified by $flashMessage into the session (to be later retrieved by flash()).
If $layout is set to 'default', the message is stored as '<div class="message">'.
$flashMessage.'</div>'. If $default is set to an empty string ('') then the message is stored
just as it has been passed. If any other value is passed then the message is stored inside the Cake
view specified by $layout.
Params has been placed in this function for future usage. Check back for more info.
The $key variable allows you to store flash messages under keys. See flash() for retreiving a
flash message based off of a key.
• valid
Returns true if the session is valid. Best used before read() operations to make sure that the
session data you are trying to access is in fact valid.
• write
• string $name
• mixed $value
Writes the variable specified by $name and $value into the active session.
« Data Sanitation: The Sanitize Class | The Request Handler Component »

18 The Request Handler Component


• Edit
• Comments (0)
• History
The Request Handler component is used in Cake to determine information about the incoming
HTTP request. You can use it to better inform your controller about AJAX requests, get
information about the remote client's IP address and request type, or strip unwanted data from
output. To use the Request Handler component, you'll need to make sure it is specified in your
controller's $components array.
Plain Text View

class ThingsController extends AppController


{
var $components = array('RequestHandler');

// ...
}
1. class ThingsController extends AppController
2. {
3. var $components = array('RequestHandler');
4. // ...
5. }

Getting Client/Request Information


Let's just dive in:
• accepts
• string $type
Returns information about the content-types that the client accepts, depending on the value of
$type. If null or no value is passed, it will return an array of content-types the client accepts. If a
string is passed, it returns true if the client accepts the given type, by checking $type against the
content-type map (see setContent()). If $type is an array, each string is evaluated individually,
and accepts() will return true if just one of them matches an accepted content-type. For example:
Plain Text View

class PostsController extends AppController


{
var $components = array('RequestHandler');

function beforeFilter ()
{
if ($this->RequestHandler->accepts('html'))
{
// Execute code only if client accepts an HTML (text/html)
response
}
elseif ($this->RequestHandler->accepts('rss'))
{
// Execute RSS-only code
}
elseif ($this->RequestHandler->accepts('atom'))
{
// Execute Atom-only code
}
elseif ($this->RequestHandler->accepts('xml'))
{
// Execute XML-only code
}

if ($this->RequestHandler->accepts(array('xml', 'rss', 'atom')))


{
// Executes if the client accepts any of the above: XML, RSS or
Atom
}
}
}
1. class PostsController extends AppController
2. {
3. var $components = array('RequestHandler');
4. function beforeFilter ()
5. {
6. if ($this->RequestHandler->accepts('html'))
7. {
8. // Execute code only if client accepts an HTML (text/html) response
9. }
10. elseif ($this->RequestHandler->accepts('rss'))
11. {
12. // Execute RSS-only code
13. }
14. elseif ($this->RequestHandler->accepts('atom'))
15. {
16. // Execute Atom-only code
17. }
18. elseif ($this->RequestHandler->accepts('xml'))
19. {
20. // Execute XML-only code
21. }
22. if ($this->RequestHandler->accepts(array('xml', 'rss', 'atom')))
23. {
24. // Executes if the client accepts any of the above: XML, RSS or Atom
25. }
26. }
27. }
• getAjaxVersion
If you are using the Prototype JS libraries, you can fetch a special header it sets on AJAX
requests. This function returns the Prototype version used.
• getClientIP
Returns the remote client's IP address.
• getReferrer
Returns the server name from which the request originated.
• isAjax
Returns true if the current request was an XMLHttpRequest.
• isAtom
Returns true if the client accepts Atom feed content (application/atom+xml).
• isDelete
Returns true if the current request was via DELETE.
• isGet
Returns true if the current request was via GET.
• isMobile
Returns true if the user agent string matches a mobile web browser.
• isPost
Returns true if the current request was via POST.
• isPut
Returns true if the current request was via PUT.
• isRss
Returns true if the clients accepts RSS feed content (application/rss+xml).
• isXml
Returns true if the client accepts XML content (application/xml or text/xml).
• setContent
• string $name
• string $type
Adds a content-type alias mapping, for use with accepts() and prefers(), where $name is the
name of the mapping (string), and $type is either a string or an array of strings, each of which is
a MIME type. The built-in type mappings are as follows:
Plain Text View

// Name => Type


'js' => 'text/javascript',
'css' => 'text/css',
'html' => 'text/html',
'form' => 'application/x-www-form-urlencoded',
'file' => 'multipart/form-data',
'xhtml' => array('application/xhtml+xml', 'application/xhtml',
'text/xhtml'),
'xml' => array('application/xml', 'text/xml'),
'rss' => 'application/rss+xml',
'atom' => 'application/atom+xml'
1. // Name => Type
2. 'js' => 'text/javascript',
3. 'css' => 'text/css',
4. 'html' => 'text/html',
5. 'form' => 'application/x-www-form-urlencoded',
6. 'file' => 'multipart/form-data',
7. 'xhtml' => array('application/xhtml+xml', 'application/xhtml',
'text/xhtml'),
8. 'xml' => array('application/xml', 'text/xml'),
9. 'rss' => 'application/rss+xml',
10. 'atom' => 'application/atom+xml'

Stripping Data
Occasionally you will want to remove data from a request or output. Use the following Request
Handler functions to perform these sorts of operations.
• stripAll
• string $str
Strips the white space, images, and scripts from $str (using stripWhitespace(), stripImages(), and
stripScripts()).
• stripImages
• string $str
Strips any HTML embedded images from $str.
• stripScripts
• string $str
Strips any <script> and <style> related tags from $str.
• stripTags
• string $str
• string $tag1
• string $tag2...
Removes the tags specified by $tag1, $tag2, etc. from $str.
Plain Text View
$someString = '<font color="#FF0000"><bold>Foo</bold></font> <em>Bar</em>';

echo $this->RequestHandler->stripTags($someString, 'font', 'bold');

// output: Foo <em>Bar</em>


1. $someString = '<font color="#FF0000"><bold>Foo</bold></font>
<em>Bar</em>';
2. echo $this->RequestHandler->stripTags($someString, 'font', 'bold');
3. // output: Foo <em>Bar</em>
• stripWhiteSpace
• string $str
Strips whitespace from $str.

Other Useful Functions


The Request Handler component is especially useful when your application includes AJAX
requests. The setAjax() function is used to automatically detect AJAX requests, and set the
controller's layout to an AJAX layout for that request. The benefit here is that you can make
small modular views that can also double as AJAX views.
Plain Text View

// list.thtml
<ul>
<? foreach ($things as $thing):?>
<li><?php echo $thing;?></li>
<?endforeach;?>
</ul>

//-------------------------------------------------------------

//The list action of my ThingsController:


function list()
{
$this->RequestHandler->setAjax($this);
$this->set('things', $this->Thing->findAll());
}
1. // list.thtml
2. <ul>
3. <? foreach ($things as $thing):?>
4. <li><?php echo $thing;?></li>
5. <?endforeach;?>
6. </ul>
7. //-------------------------------------------------------------
8. //The list action of my ThingsController:
9. function list()
10. {
11. $this->RequestHandler->setAjax($this);
12. $this->set('things', $this->Thing->findAll());
13. }
When a normal browser request is made to /things/list, the unordered list is rendered inside of the
default layout for the application. If the URL is requested as part of an AJAX operation, the list
is automatically rendered in the bare AJAX layout.
« The Cake Session Component | The Security Component »

19 The Security Component


• Edit
• Comments (0)
• History
The Security component is used to secure your controller actions against malicious or errant
requests. It allows you to set up the conditions under which an action can be requested, and
optionally specify how to deal with requests that don't meet those requirements. Again, before
using the Security component, you must make sure that 'Security' is listed in your controllers'
$components array.

Protecting Controller Actions


The Security component contains two primary methods for restricting access to controller
actions:
requirePost
• string $action1
• string $action2
• string $action3...
In order for the specified actions to execute, they must be requested via POST.
requireAuth
• string $action1
• string $action2
• string $action3...
Ensures that a request is coming from within the application by checking an authentication key
in the POST'ed form data against an authentication key stored in the user's session. If they match,
the action is allowed to execute. Be aware, however, that for reasons of flexibility, this check is
only run if form data has actually been posted. If the action is called with a regular GET request,
requireAuth() will do nothing. For maximum security, you should use requirePost() and
requireAuth() on actions that you want fully protected. Learn more about how the authentication
key is generated, and how it ends up where it should in Section 4 below.
But first, let's take a look at a simple example:
Plain Text View

class ThingsController extends AppController


{
var $components = array('Security');

function beforeFilter()
{
$this->Security->requirePost('delete');
}

function delete($id)
{
// This will only happen if the action is called via an HTTP POST
request
$this->Thing->del($id);
}
}
1. class ThingsController extends AppController
2. {
3. var $components = array('Security');
4. function beforeFilter()
5. {
6. $this->Security->requirePost('delete');
7. }
8. function delete($id)
9. {
10. // This will only happen if the action is called via an HTTP POST
request
11. $this->Thing->del($id);
12. }
13. }
Here, we're telling the Security component that the 'delete' action requires a POST request. The
beforeFilter() method is usually where you'll want to tell Security (and most other
components) what to do with themselves. It will then go do what it's told right after
beforeFilter() is called, but right before the action itself is called.
And that's about all there is to it. You can test this by typing the URL for the action into your
browser and seeing what happens.

Handling Invalid Requests


So if a request doesn't meet the security requirements that we define, what happens to it? By
default, the request is black-holed, which means that the client is sent a 404 header, and the
application immediately exits. However, the Security component has a $blackHoleCallback
property, which you can set to the name of a custom callback function defined in your controller.
Rather than simply give a 404 header and then nothing, this property allows you to perform some
additional checking on the request, redirect the request to another location, or even log the IP
address of the offending client. However, if you choose to use a custom callback, it is your
responsibility to exit the application if the request is invalid. If your callback returns true, then
the Security component will continue to check the request against other defined requirements.
Otherwise, it stops checking, and your application continues uninhibited.

Advanced Request Authentication


The requireAuth() method allows you to be very detailed in specifying how and from where
an action can be accessed, but it comes with certain usage stipulations, which become clear when
you understand how this method of authentication works. As stated above, requireAuth()
works by comparing an authentication key in the POST data to the key stored in the user's
session data. Therefore, the Security component must be included in both the controller
recieveing the request, as well as the controller making the request.
For example, if I have an action in PostsController with a view containing a form that POSTs to
an action in CommentsController, then the Security component must be included in both
CommentsController (which is receiving the request, and actually protecting the action), as well
as PostsController (from which the request will be made).
Every time the Security component is loaded, even if it is not being used to protect an action, it
does the following things: First, it generates an authentication key using the core Security class.
Then, it writes this key to the session, along with an expiration date and some additional
information (the expiration date is determined by your session security setting in
/app/config/core.php). Next, it sets the key in your controller, to be referenced later.
Then in your view files, any form tag you generate using $html->formTag() will also contain a
hidden input field with the authentication key. That way, when the form is POSTed, the Security
component can compare that value to the value in the session on the receiving end of the request.
After that, the authentication key is regenerated, and the session is updated for the next request.
« The Request Handler Component | 1.1 Collection »

The Manual
• Edit
• Comments (2)
• History
Welcome to the CakePHP 1.1 Manual.
# View Caching
• Edit
• Comments (0)
• History
Since 0.10.9.2378_final, Cake has support for view caching (also called Full Page Caching ). No,
we are not kidding. You can now cache your layouts and views. You can also mark parts of your
views to be ignored by the caching mechanism. The feature, when used wisely, can increase the
speed of your app by a considerable amount.
When you request a URL, Cake first looks to see if the requested URL isn't already cached. If it
is, Cake bypasses the dispatcher and returns the already rendered, cached version of the page. If
the page isn't in the cache, Cake behaves normally.
If you've activated Cake's caching features, Cake will store the output of its normal operation in
the cache for future user. The next time the page is requested, Cake will fetch it from the cache.
Neat, eh? Let's dig in to see how it works.

How Does it Work ?


Activating the cache
By default, view caching is disabled. To activate it, you first need to change the value of
CACHE_CHECK in /app/config/core.php from false to true:
/app/config/core.php (partial)
Plain Text View

define ('CACHE_CHECK', true);


1. define ('CACHE_CHECK', true);
This line tells Cake that you want to enable View Caching.
In the controller for the views you want to cache you have to add the Cache helper to the helpers
array:
Plain Text View

var $helpers = array('Cache');


1. var $helpers = array('Cache');
Next, you'll need to specify what you want to cache.
The $cacheAction Controller Variable
In this section, we will show you how to tell Cake what to cache. This is done by setting a
controller variable called $cacheAction. The $cacheAction variable should be set to an array that
contains the actions you want to be cached, and the time (in seconds) you want the cache to keep
its data. The time value can also be a strtotime() friendly string (i.e. '1 day' or '60 seconds').
Let's say we had a ProductsController, with some things that we'd like to cache. The following
examples show how to use $cacheAction to tell Cake to cache certain parts of the controller's
actions.
$cacheAction Examples
Cache a few of the most oft visited product pages for six hours:
Plain Text View
var $cacheAction = array(
'view/23/' => 21600,
'view/48/' => 21600
);
1. var $cacheAction = array(
2. 'view/23/' => 21600,
3. 'view/48/' => 21600
4. );
Cache an entire action. In this case the recalled product list, for one day:
Plain Text View

var $cacheAction = array('recalled/' => 86400);


1. var $cacheAction = array('recalled/' => 86400);
If we wanted to, we could cache every action by setting it to a string that is strtotime() friendly to
indicate the caching time.
Plain Text View

var $cacheAction = "1 hour";


1. var $cacheAction = "1 hour";
You can also define caching in the actions using $this->cacheAction = array()
Marking Content in the View
There are instances where you might not want parts of a view cached. If you've got some sort of
element highlighting new products, or something similar, you might want to tell Cake to cache
the view... except for a small part.
You can tell Cake not to cache content in your views by wrapping <cake:nocache>
</cake:nocache> tags around content you want the caching engine to skip.
<cake:nocache> example
Plain Text View

<h1> New Products! </h1>


<cake:nocache>
<ul>
<?php foreach($newProducts as $product): ?>
<li>$product['name']</li>
<?endforeach;?>
</ul>
</cake:nocache>
1. <h1> New Products! </h1>
2. <cake:nocache>
3. <ul>
4. <?php foreach($newProducts as $product): ?>
5. <li>$product['name']</li>
6. <?endforeach;?>
7. </ul>
8. </cake:nocache>
Clearing the cache
First, you should be aware that Cake will automatically clear the cache if a database change has
been made. For example, if one of your views uses information from your Post model, and there
has been an INSERT, UPDATE, or DELETE made to a Post, Cake will clear the cache for that
view.
But there may be cases where you'll want to clear specific cache files yourself. To do that Cake
provides the clearCache function, which is globally available:
clearCache example
Plain Text View

//Remove all cached pages that have the controller name.


clearCache('controller');

//Remove all cached pages that have the controller_action name.


clearCache('controller_action/');

//Remove all cached pages that have the controller_action_params name.


//Note: you can have multiple params
clearCache('controller_action_params');

//You can also use an array to clear muliple caches at once.


clearCache(array('controller_action_params','controller2_action_params));
1. //Remove all cached pages that have the controller name.
2. clearCache('controller');
3. //Remove all cached pages that have the controller_action name.
4. clearCache('controller_action/');
5. //Remove all cached pages that have the controller_action_params name.
6. //Note: you can have multiple params
7. clearCache('controller_action_params');
8. //You can also use an array to clear muliple caches at once.
9. clearCache(array('controller_action_params',controller2_action_params))
;

Things To Remember
Below are a few things to remember about View Caching:
1. To enable cache you set CACHE_CHECK to true in /app/config/core.php .
2. In the controller for the views you want to cache you have to add the Cache helper to the
helpers array.
3. To cache certain URLs, use $cacheAction in the controller.
4. To stop certain parts of a view from being cached, wrap them with <cake:nocache>
</cake:nocache>
5. Cake automatically clears specific cache copies when changes are made to the database
6. To manually clear parts of the cache, use clearCache().
See comments for this section

# The Cake Blog Tutorial


• Edit
• Comments (3)
• History
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:
1. 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.
2. 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.
3. Basic PHP knowledge. The more object-oriented programming you've done, the better:
but fear not if you're a procedural fan.
4. 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!

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:
Plain Text View
/path_to_document_root
/app
/cake
/vendors
.htaccess
index.php
VERSION.txt
1. /path_to_document_root
2. /app
3. /cake
4. /vendors
5. .htaccess
6. index.php
7. VERSION.txt
Now 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.

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:
Plain Text View

/* First, create our posts table: */


CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NOT NULL,
modified DATETIME DEFAULT NOT 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());
1. /* First, create our posts table: */
2. CREATE TABLE posts (
3. id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
4. title VARCHAR(50),
5. body TEXT,
6. created DATETIME DEFAULT NOT NULL,
7. modified DATETIME DEFAULT NOT NULL
8. );
9. /* Then insert some posts for testing: */
10. INSERT INTO posts (title,body,created)
11. VALUES ('The title', 'This is the post body.', NOW());
12. INSERT INTO posts (title,body,created)
13. VALUES ('A title once again', 'And the post body follows.', NOW());
14. INSERT INTO posts (title,body,created)
15. 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.

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:
Plain Text View

var $default = array('driver' => 'mysql',


'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => 'cakeBlog',
'password' => 'c4k3-rUl3Z',
'database' => 'cake_blog_tutorial' );
1. var $default = array('driver' => 'mysql',
2. 'connect' => 'mysql_pconnect',
3. 'host' => 'localhost',
4. 'login' => 'cakeBlog',
5. 'password' => 'c4k3-rUl3Z',
6. '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.

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:
1. 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.
2. Make sure you are editing the system httpd.conf rather than a user- or site-specific
httpd.conf.
3. 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.
4. 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:
Plain Text View

define ('BASE_URL', env('SCRIPT_NAME'));


1. 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.

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
Plain Text View

<?php

class Post extends AppModel


{
var $name = 'Post';
}

?>
1. <?php
2. class Post extends AppModel
3. {
4. var $name = 'Post';
5. }
6. ?>
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".

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
Plain Text View

<?php

class PostsController extends AppController


{
var $name = 'Posts';
}

?>
1. <?php
2. class PostsController extends AppController
3. {
4. var $name = 'Posts';
5. }
6. ?>
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)
Plain Text View

<?php

class PostsController extends AppController


{
var $name = 'Posts';

function index()
{
$this->set('posts', $this->Post->findAll());
}
}

?>
1. <?php
2. class PostsController extends AppController
3. {
4. var $name = 'Posts';
5. function index()
6. {
7. $this->set('posts', $this->Post->findAll());
8. }
9. }
10. ?>
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".

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:
Plain Text View

// 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] =>
)
)
)
1. // print_r($posts) output:
2. Array
3. (
4. [0] => Array
5. (
6. [Post] => Array
7. (
8. [id] => 1
9. [title] => The title
10. [body] => This is the post body.
11. [created] => 2006-03-08 14:42:22
12. [modified] =>
13. )
14. )
15. [1] => Array
16. (
17. [Post] => Array
18. (
19. [id] => 2
20. [title] => A title once again
21. [body] => And the post body follows.
22. [created] => 2006-03-08 14:42:23
23. [modified] =>
24. )
25. )
26. [2] => Array
27. (
28. [Post] => Array
29. (
30. [id] => 3
31. [title] => Title strikes back
32. [body] => This is really exciting! Not.
33. [created] => 2006-03-08 14:42:24
34. [modified] =>
35. )
36. )
37. )
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
Plain Text View

<h1>Blog posts</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>

<!-- Here's where we loop through our $posts array, printing out post info
-->

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


<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], "/posts/view/".
$post['Post']['id']); ?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>

</table>
1. <h1>Blog posts</h1>
2. <table>
3. <tr>
4. <th>Id</th>
5. <th>Title</th>
6. <th>Created</th>
7. </tr>
8. <!-- Here's where we loop through our $posts array, printing out post
info -->
9. <?php foreach ($posts as $post): ?>
10. <tr>
11. <td><?php echo $post['Post']['id']; ?></td>
12. <td>
13. <?php echo $html->link($post['Post']['title'], "/posts/view/".
$post['Post']['id']); ?>
14. </td>
15. <td><?php echo $post['Post']['created']; ?></td>
16. </tr>
17. <?php endforeach; ?>
18.
19. </table>
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)
Plain Text View

<?php

class PostsController extends AppController


{

var $name = 'Posts';

function index()
{
$this->set('posts', $this->Post->findAll());
}

function view($id = null)


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

?>
1. <?php
2. class PostsController extends AppController
3. {
4. var $name = 'Posts';
5. function index()
6. {
7. $this->set('posts', $this->Post->findAll());
8. }
9. function view($id = null)
10. {
11. $this->Post->id = $id;
12. $this->set('post', $this->Post->read());
13. }
14. }
15. ?>
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
Plain Text View

<h1><?php echo $post['Post']['title']?></h1>

<p><small>Created: <?php echo $post['Post']['created']?></small></p>

<p><?php echo $post['Post']['body']?></p>


1. <h1><?php echo $post['Post']['title']?></h1>
2. <p><small>Created: <?php echo $post['Post']['created']?></small></p>
3. <p><?php echo $post['Post']['body']?></p>
Verify that this is working by trying the links at /posts/index or manually requesting a post by
accessing /posts/view/1.

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)
Plain Text View

<?php

class PostsController extends AppController


{
var $name = 'Posts';

function index()
{
$this->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');
}
}
}
}

?>
1. <?php
2. class PostsController extends AppController
3. {
4. var $name = 'Posts';
5. function index()
6. {
7. $this->set('posts', $this->Post->findAll());
8. }
9. function view($id)
10. {
11. $this->Post->id = $id;
12. $this->set('post', $this->Post->read());
13. }
14. function add()
15. {
16. if (!empty($this->data))
17. {
18. if ($this->Post->save($this->data))
19. {
20. $this->flash('Your post has been saved.','/posts');
21. }
22. }
23. }
24. }
25. ?>
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.

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
Plain Text View

<h1>Add Post</h1>
<form method="post" action="<?php echo $html->url('/posts/add')?>">
<p>
Title:
<?php echo $html->input('Post/title', array('size' => '40'))?>
<?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
</p>
<p>
Body:
<?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
<?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
1. <h1>Add Post</h1>
2. <form method="post" action="<?php echo $html->url('/posts/add')?>">
3. <p>
4. Title:
5. <?php echo $html->input('Post/title', array('size' => '40'))?>
6. <?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
7. </p>
8. <p>
9. Body:
10. <?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
11. <?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
12. </p>
13. <p>
14. <?php echo $html->submit('Save') ?>
15. </p>
16. </form>
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)
Plain Text View

<?php

class Post extends AppModel


{
var $name = 'Post';

var $validate = array(

'title' => VALID_NOT_EMPTY,


'body' => VALID_NOT_EMPTY

);
}

?>
1. <?php
2. class Post extends AppModel
3. {
4. var $name = 'Post';
5. var $validate = array(
6. 'title' => VALID_NOT_EMPTY,
7. 'body' => VALID_NOT_EMPTY
8. );
9. }
10. ?>
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.

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)
Plain Text View

function delete($id)
{
$this->Post->del($id);
$this->flash('The post with id: '.$id.' has been deleted.', '/posts');
}
1. function delete($id)
2. {
3. $this->Post->del($id);
4. $this->flash('The post with id: '.$id.' has been deleted.', '/posts');
5. }
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)
Plain Text View

<h1>Blog posts</h1>
<p><?php echo $html->link('Add Post', '/posts/add'); ?></p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>

<!-- Here's where we loop through our $posts array, printing out post info
-->

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


<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], '/posts/view/'.
$post['Post']['id']);?>
<?php echo $html->link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>

</table>
1. <h1>Blog posts</h1>
2. <p><?php echo $html->link('Add Post', '/posts/add'); ?></p>
3. <table>
4. <tr>
5. <th>Id</th>
6. <th>Title</th>
7. <th>Created</th>
8. </tr>
9. <!-- Here's where we loop through our $posts array, printing out post
info -->
10. <?php foreach ($posts as $post): ?>
11. <tr>
12. <td><?php echo $post['Post']['id']; ?></td>
13. <td>
14. <?php echo $html->link($post['Post']['title'], '/posts/view/'.
$post['Post']['id']);?>
15. <?php echo $html->link(
16. 'Delete',
17. "/posts/delete/{$post['Post']['id']}",
18. null,
19. 'Are you sure?'
20. )?>
21. </td>
22. <td><?php echo $post['Post']['created']; ?></td>
23. </tr>
24. <?php endforeach; ?>
25.
26. </table>
This view code also uses the HtmlHelper to prompt the user with a JavaScript confirmation
dialog before they attempt to delete a post.

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)
Plain Text View

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');
}
}
}
1. function edit($id = null)
2. {
3. if (empty($this->data))
4. {
5. $this->Post->id = $id;
6. $this->data = $this->Post->read();
7. }
8. else
9. {
10. if ($this->Post->save($this->data['Post']))
11. {
12. $this->flash('Your post has been updated.','/posts');
13. }
14. }
15. }
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
Plain Text View

<h1>Edit Post</h1>
<form method="post" action="<?php echo $html->url('/posts/edit')?>">
<?php echo $html->hidden('Post/id'); ?>
<p>
Title:
<?php echo $html->input('Post/title', array('size' => '40'))?>
<?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
</p>
<p>
Body:
<?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
<?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
1. <h1>Edit Post</h1>
2. <form method="post" action="<?php echo $html->url('/posts/edit')?>">
3. <?php echo $html->hidden('Post/id'); ?>
4. <p>
5. Title:
6. <?php echo $html->input('Post/title', array('size' => '40'))?>
7. <?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?>
8. </p>
9. <p>
10. Body:
11. <?php echo $html->textarea('Post/body', array('rows'=>'10')) ?>
12. <?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?>
13. </p>
14. <p>
15. <?php echo $html->submit('Save') ?>
16. </p>
17. </form>
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)
Plain Text View

<h1>Blog posts</h1>
<p><?php echo $html->link("Add Post", "/posts/add"); ?>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>

<!-- Here's where we loop through our $posts array, printing out post info
-->

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


<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $html->link($post['Post']['title'], '/posts/view/'.
$post['Post']['id']);?>
<?php echo $html->link(
'Delete',
"/posts/delete/{$post['Post']['id']}",
null,
'Are you sure?'
)?>
<?php echo $html->link('Edit', '/posts/edit/'.$post['Post']
['id']);?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>

</table>
1. <h1>Blog posts</h1>
2. <p><?php echo $html->link("Add Post", "/posts/add"); ?>
3. <table>
4. <tr>
5. <th>Id</th>
6. <th>Title</th>
7. <th>Created</th>
8. </tr>
9. <!-- Here's where we loop through our $posts array, printing out post
info -->
10. <?php foreach ($posts as $post): ?>
11. <tr>
12. <td><?php echo $post['Post']['id']; ?></td>
13. <td>
14. <?php echo $html->link($post['Post']['title'], '/posts/view/'.
$post['Post']['id']);?>
15. <?php echo $html->link(
16. 'Delete',
17. "/posts/delete/{$post['Post']['id']}",
18. null,
19. 'Are you sure?'
20. )?>
21. <?php echo $html->link('Edit', '/posts/edit/'.$post['Post']['id']);?>
22. </td>
23. <td><?php echo $post['Post']['created']; ?></td>
24. </tr>
25. <?php endforeach; ?>
26.
27. </table>

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:
Plain Text View

$Route->connect ('/', array('controller'=>'pages', 'action'=>'display',


'home'));
1. $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:
Plain Text View

$Route->connect ('/', array('controller'=>'posts', 'action'=>'index'));


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

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.
If you need help, come see us in #cakephp. Welcome to Cake!
See comments for this section

# Simple User Authentication


• Edit
• Comments (2)
• History
The Big Picture
If you're new to CakePHP, you'll be strongly tempted to copy and paste this code for use in your
mission critical, sensitive-data-handling production application. Resist ye: this chapter is a
discussion on Cake internals, not application security. While I doubt we'll provide for any
extremely obvious security pitfalls, the point of this example is to show you how Cake's
internals work, and allow you to create a bulletproof brute of an application on your own.
Cake has access control via its built-in ACL engine, but what about user authentication and
persistence? What about that?
Well, for now, we've found that user authentication systems vary from application to application.
Some like hashed passwords, others, LDAP authentication - and almost every app will have User
models that are slightly different. For now, we're leaving it up to you. Will this change? We're
not sure yet. For now, we think that the extra overhead of building this into the framework isn't
worth it, because creating your own user authentication setup is easy with Cake.
You need just three things:
• A way to authenticate users (usually done by verifying a user's identity with a
username/password combination)
• A way to persistently track that user as they navigate your application
(usually done with sessions)
• A way to check if a user has been authenticated (also often done by
interacting with sessions)
In this example, we'll create a simple user authentication system for a client management system.
This fictional application would probably be used by an office to track contact information and
related notes about clients. All of the system functionality will be placed behind our user
authentication system except for few bare-bones, public-safe views that shows only the names
and titles of clients stored in the system.
We'll start out by showing you how to verify users that try to access the system. Authenticated
user info will be stored in a PHP session using Cake's Session Component. Once we've got user
info in the session, we'll place checks in the application to make sure application users aren't
entering places they shouldn't be.
One thing to note - authentication is not the same as access control. All we're after in this
example is how to see if people are who they say they are, and allow them basic access to parts
of the application. If you want to fine tune this access, check out the chapter on Cake's Access
Control Lists. We'll make notes as to where ACLs might fit in, but for now, let's focus on simple
user authentication.
I should also say that this isn't meant to serve as some sort of primer in application security. We
just want to give you enough to work with so you can build bulletproof apps of your own.
Authentication and Persistence
First, we need a way to store information about users trying to access our client management
system. The client management system we're using stores user information in a database table
that was created using the following SQL:
Table 'users', Fictional Client Management System Database
Plain Text View

CREATE TABLE `users` (


`id` int(11) NOT NULL auto_increment,
`username` varchar(255) NOT NULL,
`password` varchar(32) NOT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
1. CREATE TABLE `users` (
2. `id` int(11) NOT NULL auto_increment,
3. `username` varchar(255) NOT NULL,
4. `password` varchar(32) NOT NULL,
5. `first_name` varchar(255) NOT NULL,
6. `last_name` varchar(255) NOT NULL,
7. PRIMARY KEY (`id`)
8. )
Pretty simple, right? The Cake Model for this table can be pretty bare:
Plain Text View

<?php
class User extends AppModel
{
var $name = 'User';
}
?>
1. <?php
2. class User extends AppModel
3. {
4. var $name = 'User';
5. }
6. ?>
First thing we'll need is a login view and action. This will provide a way for application users to
attempt logins and a way for the system to process that information to see if they should be
allowed to access the system or not. The view is just a HTML form, created with the help of
Cake's Html Helper:
/app/views/users/login.thtml
Plain Text View

<?php if ($error): ?>


<p>The login credentials you supplied could not be recognized. Please try
again.</p>
<?php endif; ?>

<form action="<?php echo $html->url('/users/login'); ?>" method="post">


<div>
<label for="username">Username:</label>
<?php echo $html->input('User/username', array('size' => 20)); ?>
</div>
<div>
<label for="password">Password:</label>
<?php echo $html->password('User/password', array('size' => 20)); ?>
</div>
<div>
<?php echo $html->submit('Login'); ?>
</div>
</form>
1. <?php if ($error): ?>
2. <p>The login credentials you supplied could not be recognized. Please
try again.</p>
3. <?php endif; ?>
4.
5. <form action="<?php echo $html->url('/users/login'); ?>" method="post">
6. <div>
7. <label for="username">Username:</label>
8. <?php echo $html->input('User/username', array('size' => 20)); ?>
9. </div>
10. <div>
11. <label for="password">Password:</label>
12. <?php echo $html->password('User/password', array('size' => 20)); ?>
13. </div>
14. <div>
15. <?php echo $html->submit('Login'); ?>
16. </div>
17. </form>
This view presents a simple login form for users trying to access the system. The action for the
form is /users/login, which is in the UsersController and looks like this:
/app/controllers/users_controller.php (partial)
Plain Text View

<?php
class UsersController extends AppController
{
function login()
{
//Don't show the error message if no data has been submitted.
$this->set('error', false);

// If a user has submitted form data:


if (!empty($this->data))
{
// First, let's see if there are any users in the database
// with the username supplied by the user using the form:

$someone = $this->User->findByUsername($this->data['User']
['username']);

// At this point, $someone is full of user data, or its empty.


// Let's compare the form-submitted password with the one in
// the database.

if(!empty($someone['User']['password']) && $someone['User']


['password'] == $this->data['User']['password'])
{
// Note: hopefully your password in the DB is hashed,
// so your comparison might look more like:
// md5($this->data['User']['password']) == ...

// This means they were the same. We can now build some basic
// session information to remember this user as 'logged-in'.
$this->Session->write('User', $someone['User']);

// Now that we have them stored in a session, forward them on


// to a landing page for the application.

$this->redirect('/clients');
}
// Else, they supplied incorrect data:
else
{
// Remember the $error var in the view? Let's set that to
true:
$this->set('error', true);
}
}
}

function logout()
{
// Redirect users to this action if they click on a Logout button.
// All we need to do here is trash the session information:

$this->Session->delete('User');

// And we should probably forward them somewhere, too...

$this->redirect('/');
}
}
?>
1. <?php
2. class UsersController extends AppController
3. {
4. function login()
5. {
6. //Don't show the error message if no data has been submitted.
7. $this->set('error', false);
8. // If a user has submitted form data:
9. if (!empty($this->data))
10. {
11. // First, let's see if there are any users in the database
12. // with the username supplied by the user using the form:
13. $someone = $this->User->findByUsername($this->data['User']['username']);
14. // At this point, $someone is full of user data, or its empty.
15. // Let's compare the form-submitted password with the one in
16. // the database.
17. if(!empty($someone['User']['password']) && $someone['User']['password']
== $this->data['User']['password'])
18. {
19. // Note: hopefully your password in the DB is hashed,
20. // so your comparison might look more like:
21. // md5($this->data['User']['password']) == ...
22. // This means they were the same. We can now build some basic
23. // session information to remember this user as 'logged-in'.
24. $this->Session->write('User', $someone['User']);
25. // Now that we have them stored in a session, forward them on
26. // to a landing page for the application.
27. $this->redirect('/clients');
28. }
29. // Else, they supplied incorrect data:
30. else
31. {
32. // Remember the $error var in the view? Let's set that to true:
33. $this->set('error', true);
34. }
35. }
36. }
37. function logout()
38. {
39. // Redirect users to this action if they click on a Logout button.
40. // All we need to do here is trash the session information:
41. $this->Session->delete('User');
42. // And we should probably forward them somewhere, too...
43.
44. $this->redirect('/');
45. }
46. }
47. ?>
Not too bad: the contents of the login() action could be less than 20 lines if you were concise.
The result of this action is either 1: the user information is entered into the session and forwarded
to the landing page of the app, or 2: kicked back to the login screen and presented the login form
(with an additional error message).
Access Checking in your Application
Now that we can authenticate users, let's make it so the application will kick out users who try to
enter the system from points other than the login screen and the "basic" client directory we
detailed earlier.
One way to do this is to create a function in the AppController that will do the session checking
and kicking for you.
/app/app_controller.php
Plain Text View

<?php
class AppController extends Controller
{
function checkSession()
{
// If the session info hasn't been set...
if (!$this->Session->check('User'))
{
// Force the user to login
$this->redirect('/users/login');
exit();
}
}
}
?>
1. <?php
2. class AppController extends Controller
3. {
4. function checkSession()
5. {
6. // If the session info hasn't been set...
7. if (!$this->Session->check('User'))
8. {
9. // Force the user to login
10. $this->redirect('/users/login');
11. exit();
12. }
13. }
14. }
15. ?>
Now you have a function you can use in any controller to make sure users aren't trying to access
controller actions without logging in first. Once this is in place you can check access at any level
- here are some examples:
Forcing authentication before all actions in a controller
Plain Text View

<?php
class NotesController extends AppController
{
// Don't want non-authenticated users looking at any of the actions
// in this controller? Use a beforeFilter to have Cake run checkSession
// before any action logic.

function beforeFilter()
{
$this->checkSession();
}
}
?>
1. <?php
2. class NotesController extends AppController
3. {
4. // Don't want non-authenticated users looking at any of the actions
5. // in this controller? Use a beforeFilter to have Cake run checkSession
6. // before any action logic.
7. function beforeFilter()
8. {
9. $this->checkSession();
10. }
11. }
12. ?>
Forcing authentication before a single controller action
Plain Text View

<?php
class NotesController extends AppController
{
function publicNotes($clientID)
{
// Public access to this action is okay...
}

function edit($noteId)
{
// But you only want authenticated users to access this action.
$this->checkSession();
}
}
?>
1. <?php
2. class NotesController extends AppController
3. {
4. function publicNotes($clientID)
5. {
6. // Public access to this action is okay...
7. }
8. function edit($noteId)
9. {
10. // But you only want authenticated users to access this action.
11. $this->checkSession();
12. }
13. }
14. ?>
Now that you have the basics down, you might want to venture out on your own and implement
some advanced or customized features past what has been outlined here. Integration with Cake's
ACL component might be a good first step.
See comments for this section

# Cake Conventions
• Edit
• Comments (0)
• History
Conventions, eh ?
Yes, conventions. According to thefreedictionary:
• General agreement on or acceptance of certain practices or attitudes: By
convention, north is at the top of most maps.
• A practice or procedure widely observed in a group, especially to facilitate
social interaction; a custom: the convention of shaking hands.
• A widely used and accepted device or technique, as in drama, literature, or
painting: the theatrical convention of the aside.
Conventions in cake are what make the magic happen, read it automagic.
Needless to say by favorizing convention over configuration, Cake makes your
productivity increase to a scary level without any loss to flexibility. Conventions in
cake are really simple and intuitive. They were extracted from the best practices
good web developers have used throughout the years in the field of web
developement.
Filenames
Filenames are underscore. As a general rule, if you have a class MyNiftyClass, then in Cake, its
file should be named my_nifty_class.php.
So if you find a snippet you automatically know that:
• If it's a Controller named KissesAndHugsController, then its filename must
be kisses_and_hugs_controller.php (notice _controller in the filename)
• If it's a Model named OptionValue, then its filename must be
option_value.php
• If it's a Component named MyHandyComponent, then its filename must be
my_handy.php(no need for _component in the filename)
• If it's a Helper named BestHelperEver, then its filename must be
best_helper_ever.php
Models
• Model class names are singular.
• Model class names are Capitalized for single-word models, and
UpperCamelCased for multi-word models.
○ Examples: Person, Monkey, GlassDoor, LineItem, ReallyNiftyThing
• many-to-many join tables should be named:
alphabetically_first_table_plural_alphabetically_second_table_plural ie:
tags_users
• Model filenames use a lower-case underscored syntax.
○ Examples: person.php, monkey.php, glass_door.php, line_item.php,
really_nifty_thing.php
• Database tables related to models also use a lower-case underscored syntax
- but they are plural.
○ Examples: people, monkeys, glass_doors, line_items,
really_nifty_things
CakePHP naming conventions are meant to streamline code creation and make code more
readable. If you find it getting in your way, you can override it.
• Model name: Set var $name in your model definition.
• Model-related database tables: Set var $useTable in your model definition.
Controllers
• Controller class names are plural.
• Controller class names are Capitalized for single-word controllers, and
UpperCamelCased for multi-word controllers. Controller class names also end
with 'Controller'.
○ Examples: PeopleController, MonkeysController, GlassDoorsController,
LineItemsController, ReallyNiftyThingsController
• Controller file names use a lower-case underscored syntax. Controller file
names also end with '_controller'. So if you have a controller class called
PostsController, the controller file name should be posts_controller.php
○ Examples: people_controller.php, monkeys_controller.php,
glass_doors_controller.php, line_items_controller.php,
really_nifty_things_controller.php
• For protected member visibility, controller action names should be prepended
with '-'.
• For private member visibility, controller action names should be prepended
with '__'.
Views
• Views are named after actions they display.
• Name the view file after action name, in lowercase.
○ Examples: PeopleController::worldPeace() expects a view in
/app/views/people/world_peace.thtml;
MonkeysController::banana() expects a view in
/app/views/monkeys/banana.thtml.
You can force an action to render a specific view by calling $this-
>render('name_of_view_file_without_dot_thtml'); at the end of your action.
Helpers
• Helper classname is CamelCased and ends in "Helper", the filename is
underscored.
○ Example: class MyHelperHelper extends Helper is in
/app/views/helpers/my_helper.php.
Include in the controller with var $helpers = array('Html','MyHelper'); in the view you can access
with $myHelper->method().
Components
• Component classname is CamelCased and ends in "Component", the
filename is underscored.
○ Example: class MyComponentComponent extends Object is in
/app/controllers/components/my_component.php.
Include in the controller with var $components = array('MyComponent'); in the controller you
can access with $this->MyComponent->method().
Vendors
Vendors don't follow any convention for obvious reasons: they are third-party pieces of code,
Cake has no control over them.
See comments for this section

« 1.1 Collection | Preface »


1 Preface
• Edit
• Comments (0)
• History
Audience
This manual is written for people who want to build web applications faster and more enjoyably.
CakePHP aims to assist PHP users of all levels to create robust, maintainable applications
quickly and easily.
This manual expects a basic knowledge of PHP and HTML. A familiarity with the Model-View-
Controller programming pattern is helpful, but we will cover that along the way for those new to
MVC. While this work will attempt to aid the reader in configuring and troubleshooting their
web server, a full coverage of such issues is outside the scope of this manual.
Rudimentary knowledge in first aid (CPR), basic survival skills, dating & relationships is also
generally recommended, though also outside the scope of this document.
CakePHP is Free
CakePHP is free. You don't have to pay for it, you can use it any way you want. CakePHP is
developed under the MIT License. CakePHP is an Open Source project, this means you have full
access to the source code. The best place to get the most recent version is at the CakePHP web
site (http://www.cakephp.org). You can also browse the latest and greatest code there.
Community
CakePHP is developed by a hard working community of people. They come from different
countries all over the world and joined together to create the CakePHP framework for the benefit
of the widest audience possible. For more information about Cake's active developer and user
communities, visit http://www.cakephp.org.
Our IRC channel is always filled with knowledgable, friendly Bakers. If you're stuck on a bit of
code, need a listening ear, or want to start an argument about coding conventions, drop on by:
we'd love to hear from you. Visit us at #cakephp on irc.freenode.com.
« The Manual | Introduction to CakePHP »

Install CakePHP
Ok, now that the database is squared away, you need to download cakePHP, which you can't
really miss on their site. Once you have it downloaded, all you have to do is put the cake folder
in your root www directory or anywhere available on your local server. And that's it. Not real
installation, just a few files to copy and settings to configure.
Default cake home page
Now that you have cake on your server, you can actually go to localhost/cakephp_directory
and you will see the nice default cakephp page. While it is interesting to see what cake can do
without touching it, you have to setup a database configuration to get things going.
Cake's Database Configuration
First you need to make a copy of the database.php.default configuration file found in
cake_directory/app/config. Make sure you make a copy inside the same folder, after that
just take off the .default and you have you blank configuration file. Using you favorite text or
code editor, open it up, and after scrolling down a bit, you should see:
class DATABASE_CONFIG
{
var $default = array('driver' => 'mysql',
'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name',
'prefix' => '');

var $test = array('driver' => 'mysql',


'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name-test',
'prefix' => '');
}
First off, you probably notice there is actually two database setups there. This is because cake
can actually handle more than just one database at a time, you can even add more than two. For
our purposes, however, we need only one, so you can delete the second one. Most of the stuff
should be pretty straight forward, with our complete database config file looking like so:
class DATABASE_CONFIG
{
var $default = array('driver' => 'mysql',
'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cakephp',
'prefix' => '');
}
If you open up your cake app in a browser you will see the default cake page, with two extra
messages letting you know that you database is setup and connectible. This is really good news,
and means that we are pretty much ready to start building our first app. But that is for the next
tutorial. For now you can take a break, and be glad your cake app is ready to be built. That's it
for this one, but don't forget that when you need some programming assistance, just Switch On
The Code.

Log
How To Install CakePHP in a Subdirectory Via an Apache Alias
The documentation on how to install CakePHP in a non-root directory
(http://site.tld/directory_name/) is rather sparse, so here’s how to do it using an Apache Alias
directive:
httpd.conf
In httpd.conf, add the following line:
Alias /directory_name /absolute/path/to/install/directory/app/webroot

.htaccess
In app/webroot/.htaccess, add the following line:
RewriteBase /directory_name
Your .htaccess file should now appear as such:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /directory_name
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

index.php
Finally, in app/webroot/index.php, at line 63, right below where it says not to edit below this
line, change it to:
define('WEBROOT_DIR', 'directory_name');

Make it Work
Restart Apache and you should be all set.

3.12 Scaffolding
• Translate
• Comments (0)
• History
There is no translation yet for this section. Please help out and translate this.. More information
about translations
Application scaffolding is a technique that allows a developer to define and create a basic
application that can create, retrieve, update and delete objects. Scaffolding in CakePHP also
allows developers to define how objects are related to each other, and to create and break those
links.
All that’s needed to create a scaffold is a model and its controller. Once you set the $scaffold
variable in the controller, you’re up and running.
CakePHP’s scaffolding is pretty cool. It allows you to get a basic CRUD application up and
going in minutes. So cool that you'll want to use it in production apps. Now, we think its cool
too, but please realize that scaffolding is... well... just scaffolding. It's a loose structure you throw
up real quick during the beginning of a project in order to get started. It isn't meant to be
completely flexible, it’s meant as a temporary way to get up and going. If you find yourself
really wanting to customize your logic and your views, its time to pull your scaffolding down in
order to write some code. CakePHP’s Bake console, covered in the next section, is a great next
step: it generates all the code that would produce the same result as the most current scaffold.
Scaffolding is a great way of getting the early parts of developing a web application started.
Early database schemas are subject to change, which is perfectly normal in the early part of the
design process. This has a downside: a web developer hates creating forms that never will see
real use. To reduce the strain on the developer, scaffolding has been included in CakePHP.
Scaffolding analyzes your database tables and creates standard lists with add, delete and edit
buttons, standard forms for editing and standard views for inspecting a single item in the
database.
To add scaffolding to your application, in the controller, add the $scaffold variable:
Plain Text View

<?php

class CategoriesController extends AppController {


var $scaffold;
}

?>
1. <?php
2. class CategoriesController extends AppController {
3. var $scaffold;
4. }
5. ?>
Assuming you’ve created even the most basic Category model class file (in
/app/models/category.php), you’re ready to go. Visit http://example.com/categories to see your
new scaffold.
Creating methods in controllers that are scaffolded can cause unwanted results. For example, if
you create an index() method in a scaffolded controller, your index method will be rendered
rather than the scaffolding functionality.
Scaffolding is knowledgeable about model associations, so if your Category model belongsTo a
User, you’ll see related User IDs in the Category listings. While scaffolding "knows" about
model associations, you will not see any related records in the scaffold views until you manually
add the association code to the model. For example, if Group hasMany User and User belongsTo
Group, you have to manually add the following code in your User and Group models. Before you
add the following code, the view displays an empty select input for Group in the New User form.
After you add the following code, the view displays a select input populated with IDs or names
from the Group table in the New User form.
Plain Text View

// In group.php
var $hasMany = 'User';
// In user.php
var $belongsTo = 'Group';
1. // In group.php
2. var $hasMany = 'User';
3. // In user.php
4. var $belongsTo = 'Group';
If you’d rather see something besides an ID (like the user’s first name), you can set the
$displayField variable in the model. Let’s set the $displayField variable in our User class so that
users related to categories will be shown by first name rather than just an ID in scaffolding. This
feature makes scaffolding more readable in many instances.
Plain Text View

<?php

class User extends AppModel {


var $name = 'User';
var $displayField = 'first_name';
}

?>
1. <?php
2. class User extends AppModel {
3. var $name = 'User';
4. var $displayField = 'first_name';
5. }

7.3.1 Creating Forms


• Edit
• Comments (3)
• History
The first method you’ll need to use in order to take advantage of the FormHelper is create().
This special method outputs an opening form tag.
create(string $model = null, array $options = array())
All parameters are optional. If create() is called with no parameters supplied, it assumes you
are building a form that submits to the current controller, via either the add() or edit() action.
The default method for form submission is POST. The form element also is returned with a
DOM ID. The ID is generated using the name of the model, and the name of the controller
action, CamelCased. If I were to call create() inside a UsersController view, I’d see something
like the following output in the rendered view:
Plain Text View

<form id="UserAddForm" method="post" action="/users/add">


1. <form id="UserAddForm" method="post" action="/users/add">
You can also pass false for $model. This will place your form data into the array: $this->data
(instead of in the sub-array: $this->data['Model']). This can be handy for short forms that
may not represent anything in your database.
The create() method allows us to customize much more using the parameters, however. First,
you can specify a model name. By specifying a model for a form, you are creating that form's
context. All fields are assumed to belong to this model (unless otherwise specified), and all
models referenced are assumed to be associated with it. If you do not specify a model, then it
assumes you are using the default model for the current controller.
Plain Text View

<?php echo $form->create('Recipe'); ?>

//Output:
<form id="RecipeAddForm" method="post" action="/recipes/add">
1. <?php echo $form->create('Recipe'); ?>
2.
3. //Output:
4. <form id="RecipeAddForm" method="post" action="/recipes/add">
This will POST the form data to the add() action of RecipesController. However, you can also
use the same logic to create an edit form. The FormHelper uses the $this->data property to
automatically detect whether to create an add or edit form. If $this->data contains an array
element named after the form's model, and that array contains a non-empty value of the model's
primary key, then the FormHelper will create an edit form for that record. For example, if we
browse to http://site.com/recipes/edit/5, we might get the following:
Plain Text View

// controllers/recipes_controller.php:
<?php
function edit($id = null) {
if (empty($this->data)) {
$this->data = $this->Recipe->findById($id);
} else {
// Save logic goes here
}
}
?>

// views/recipes/edit.ctp:

// Since $this->data['Recipe']['id'] = 5, we should get an edit form


<?php echo $form->create('Recipe'); ?>

//Output:
<form id="RecipeEditForm" method="post" action="/recipes/edit/5">
<input type="hidden" name="_method" value="PUT" />
1. // controllers/recipes_controller.php:
2. <?php
3. function edit($id = null) {
4. if (empty($this->data)) {
5. $this->data = $this->Recipe->findById($id);
6. } else {
7. // Save logic goes here
8. }
9. }
10. ?>
11.
12. // views/recipes/edit.ctp:
13. // Since $this->data['Recipe']['id'] = 5, we should get an edit form
14. <?php echo $form->create('Recipe'); ?>
15.
16. //Output:
17. <form id="RecipeEditForm" method="post" action="/recipes/edit/5">
18. <input type="hidden" name="_method" value="PUT" />
Since this is an edit form, a hidden input field is generated to override the default HTTP method.
The $options array is where most of the form configuration happens. This special array can
contain a number of different key-value pairs that affect the way the form tag is generated.
7.3.1.1 $options[‘type’]
• Edit
• View just this section
• Comments (0)
• History
This key is used to specify the type of form to be created. Valid values include ‘post’, ‘get’,
‘file’, ‘put’ and ‘delete’.
Supplying either ‘post’ or ‘get’ changes the form submission method accordingly.
Plain Text View

<?php echo $form->create('User', array('type' => 'get')); ?>

//Output:
<form id="UserAddForm" method="get" action="/users/add">
1. <?php echo $form->create('User', array('type' => 'get')); ?>
2.
3. //Output:
4. <form id="UserAddForm" method="get" action="/users/add">
Specifying ‘file’ changes the form submission method to ‘post’, and includes an enctype of
“multipart/form-data” on the form tag. This is to be used if there are any file elements inside the
form. The absence of the proper enctype attribute will cause the file uploads not to function.
Plain Text View
<?php echo $form->create('User', array('type' => 'file')); ?>

//Output:
<form id="UserAddForm" enctype="multipart/form-data" method="post"
action="/users/add">
1. <?php echo $form->create('User', array('type' => 'file')); ?>
2.
3. //Output:
4. <form id="UserAddForm" enctype="multipart/form-data" method="post"
action="/users/add">
When using ‘put’ or ‘delete’, your form will be functionally equivalent to a 'post' form, but when
submitted, the HTTP request method will be overridden with 'PUT' or 'DELETE', respectively.
This allows CakePHP to emulate proper REST support in web browsers.
See comments for this section

7.3.1.2 $options[‘action’]
• Edit
• View just this section
• Comments (0)
• History
The action key allows you to point the form to a specific action in your current controller. For
example, if you’d like to point the form to the login() action of the current controller, you would
supply an $options array like the following:
Plain Text View

<?php echo $form->create('User', array('action' => 'login')); ?>

//Output:
<form id="UserLoginForm" method="post" action="/users/login">
</form>
1. <?php echo $form->create('User', array('action' => 'login')); ?>
2.
3. //Output:
4. <form id="UserLoginForm" method="post" action="/users/login">
5. </form>
See comments for this section
7.3.1.3 $options[‘url’]
• Edit
• View just this section
• Comments (2)
• History
If the desired form action isn’t in the current controller, you can specify a URL for the form
action using the ‘url’ key of the $options array. The supplied URL can be relative to your
CakePHP application, or can point to an external domain.
Plain Text View

<?php echo $form->create(null, array('url' => '/recipes/add')); ?>


// or
<?php echo $form->create(null, array('url' => array('controller' =>
'recipes', 'action' => 'add'))); ?>

//Output:
<form method="post" action="/recipes/add">

<?php echo $form->create(null, array(


'url' => 'http://www.google.com/search',
'type' => 'get'
)); ?>

//Output:
<form method="get" action="http://www.google.com/search">
1. <?php echo $form->create(null, array('url' => '/recipes/add')); ?>
2. // or
3. <?php echo $form->create(null, array('url' => array('controller' =>
'recipes', 'action' => 'add'))); ?>
4.
5. //Output:
6. <form method="post" action="/recipes/add">
7.
8. <?php echo $form->create(null, array(
9. 'url' => 'http://www.google.com/search',
10. 'type' => 'get'
11. )); ?>
12.
13. //Output:
14. <form method="get" action="http://www.google.com/search">

Also check HtmlHelper::url method for more examples of different types of urls.
See comments for this section

7.3.1.4 $options[‘default’]
• Edit
• View just this section
• Comments (0)
• History
If ‘default’ has been set to boolean false, the form’s submit action is changed so that pressing the
submit button does not submit the form. If the form is meant to be submitted via AJAX, setting
‘default’ to false suppresses the form’s default behavior so you can grab the data and submit it
via AJAX instead.

7.3.2 Closing the Form


• Edit
• Comments (2)
• History
The FormHelper also includes an end() method that completes the form markup. Often, end()
only outputs a closing form tag, but using end() also allows the FormHelper to insert needed
hidden form elements other methods may be depending on.
Plain Text View

<?php echo $form->create(); ?>

<!-- Form elements go here -->

<?php echo $form->end(); ?>


1. <?php echo $form->create(); ?>
2.
3. <!-- Form elements go here -->
4.
5. <?php echo $form->end(); ?>
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.
Plain Text View

<?php echo $form->end('Finish'); ?>

1. <?php echo $form->end('Finish'); ?>


Will output:

<div class="submit">
<input type="submit" value="Finish" />
</div>
</form>
You can specify detail settings by passing an array to end().
Plain Text View

<?php
$options = array(
'name' => 'Update'
'label' => 'Update!',
'div' => array(
'class' => 'glass-pill',
)
);
echo $form->end($options);
1. <?php
2. $options = array(
3. 'name' => 'Update'
4. 'label' => 'Update!',
5. 'div' => array(
6. 'class' => 'glass-pill',
7. )
8. );
9. echo $form->end($options);
Will output:
<div class="glass-pill"><input type="submit" value="Update!"
name="Update"></div>
See the API for further details.
« $options[‘default’] | Automagic Form Elements »

7.3.3 Automagic Form Elements


• Edit
• Comments (4)
• History
First, let’s look at some of the more automatic form creation methods in the FormHelper. The
main method we’ll look at is input(). This method will automatically inspect the model field it
has been supplied in order to create an appropriate input for that field.
input(string $fieldName, array $options = array())

Column Type Resulting Form Field


string (char, varchar, etc.) text

boolean, tinyint(1) checkbox

text textarea

text, with name of password, passwd,


password
or psword

date day, month, and year selects

day, month, year, hour, minute, and


datetime, timestamp
meridian selects

time hour, minute, and meridian selects

For example, let’s assume that my User model includes fields for a username (varchar),
password (varchar), approved (datetime) and quote (text). I can use the input() method of the
FormHelper to create appropriate inputs for all of these form fields.
Plain Text View

<?php echo $form->create(); ?>

<?php
echo $form->input('username'); //text
echo $form->input('password'); //password
echo $form->input('approved'); //day, month, year, hour, minute,
meridian
echo $form->input('quote'); //textarea
?>

<?php echo $form->end('Add'); ?>


1. <?php echo $form->create(); ?>
2.
3. <?php
4. echo $form->input('username'); //text
5. echo $form->input('password'); //password
6. echo $form->input('approved'); //day, month, year, hour, minute,
meridian
7. echo $form->input('quote'); //textarea
8. ?>
9.
10. <?php echo $form->end('Add'); ?>
A more extensive example showing some options for a date field:
Plain Text View
echo $form->input('birth_dt', array( 'label' => 'Date of birth'
, 'dateFormat' => 'DMY'
, 'minYear' => date('Y') - 70
, 'maxYear' => date('Y') - 18 ));
1. echo $form->input('birth_dt', array( 'label' => 'Date of birth'
2. , 'dateFormat' => 'DMY'
3. , 'minYear' => date('Y') - 70
4. , 'maxYear' => date('Y') - 18 ));
Besides the specific input options found below you can specify any html attribute (for instance
onfocus). For more information on $options and $htmlAttributes see HTML Helper.
And to round off, here's an example for creating a hasAndBelongsToMany select. Assume that
User hasAndBelongsToMany Group. In your controller, set a camelCase plural variable (group
-> groups in this case, or ExtraFunkyModel -> extraFunkyModels) with the select options. In the
controller action you would put the following:
Plain Text View

$this->set('groups', $this->User->Group->find('list'));
1. $this->set('groups', $this->User->Group->find('list'));
And in the view a multiple select can be expected with this simple code:
Plain Text View

echo $form->input('Group');
1. echo $form->input('Group');
If you want to create a select field while using a belongsTo- or hasOne-Relation, you can add the
following to your Users-controller (assuming your User belongsTo Group):
Plain Text View

$this->set('groups', $this->User->Group->find('list'));
1. $this->set('groups', $this->User->Group->find('list'));
Afterwards, add the following to your form-view:
Plain Text View

echo $form->input('group_id');
1. echo $form->input('group_id');
If your model name consists of two or more words, e.g., "UserGroup", when passing the data
using set() you should name your data in a pluralised and camelCased format as follows:
Plain Text View

$this->set('userGroups', $this->UserGroup->find('list'));
// or
$this->set('reallyInappropriateModelNames', $this-
>ReallyInappropriateModelName->find('list'));
1. $this->set('userGroups', $this->UserGroup->find('list'));
2. // or
3. $this->set('reallyInappropriateModelNames', $this-
>ReallyInappropriateModelName->find('list'));

7.3.3.1 Field naming convention


• Edit
• View just this section
• Comments (0)
• History
The Form helper is pretty smart. Whenever you specify a field name with the form helper
methods, it'll automatically use the current model name to build an input with a format like the
following:
Plain Text View

<input type="text" id="ModelnameFieldname" name="data[Modelname][fieldname]">


1. <input type="text" id="ModelnameFieldname" name="data[Modelname]
[fieldname]">
You can manually specify the model name by passing in Modelname.fieldname as the first
parameter.
Plain Text View

echo $form->input('Modelname.fieldname');
1. echo $form->input('Modelname.fieldname');
If you need to specify multiple fields using the same field name, thus creating an array that can
be saved in one shot with saveAll(), use the following convention:
Plain Text View

<?php
echo $form->input('Modelname.0.fieldname');
echo $form->input('Modelname.1.fieldname');
?>

<input type="text" id="Modelname0Fieldname" name="data[Modelname][0]


[fieldname]">
<input type="text" id="Modelname1Fieldname" name="data[Modelname][1]
[fieldname]">
1. <?php
2. echo $form->input('Modelname.0.fieldname');
3. echo $form->input('Modelname.1.fieldname');
4. ?>
5.
6. <input type="text" id="Modelname0Fieldname" name="data[Modelname][0]
[fieldname]">
7. <input type="text" id="Modelname1Fieldname" name="data[Modelname][1]
[fieldname]">
See comments for this section
7.3.3.2 $options[‘type’]
• Edit
• View just this section
• Comments (2)
• History
You can force the type of an input (and override model introspection) by specifying a type. In
addition to the field types found in the table above, you can also create ‘file’, and ‘password’
inputs.
Plain Text View

<?php echo $form->input('field', array('type' => 'file')); ?>

Output:

<div class="input">
<label for="UserField">Field</label>
<input type="file" name="data[User][field]" value="" id="UserField" />
</div>
1. <?php echo $form->input('field', array('type' => 'file')); ?>
2.
3. Output:
4.
5. <div class="input">
6. <label for="UserField">Field</label>
7. <input type="file" name="data[User][field]" value="" id="UserField" />
8. </div>
See comments for this section
7.3.3.3 $options[‘before’], $options[‘between’], $options[‘separator’] and
$options[‘after’]
• Edit
• View just this section
• Comments (0)
• History
Use these keys if you need to inject some markup inside the output of the input() method.
Plain Text View

<?php echo $form->input('field', array(


'before' => '--before--',
'after' => '--after--',
'between' => '--between---'
));?>

Output:

<div class="input">
--before--
<label for="UserField">Field</label>
--between---
<input name="data[User][field]" type="text" value="" id="UserField" />
--after--
</div>
1. <?php echo $form->input('field', array(
2. 'before' => '--before--',
3. 'after' => '--after--',
4. 'between' => '--between---'
5. ));?>
6.
7. Output:
8.
9. <div class="input">
10. --before--
11. <label for="UserField">Field</label>
12. --between---
13. <input name="data[User][field]" type="text" value="" id="UserField" />
14. --after--
15. </div>
For radio type input the 'separator' attribute can be used to inject markup to separate each
input/label pair.
Plain Text View

<?php echo $form->input('field', array(


'before' => '--before--',
'after' => '--after--',
'between' => '--between---',
'separator' => '--separator--',
'options' => array('1', '2')
));?>

Output:

<div class="input">
--before--
<input name="data[User][field]" type="radio" value="1" id="UserField1" />
<label for="UserField1">1</label>
--separator--
<input name="data[User][field]" type="radio" value="2" id="UserField2" />
<label for="UserField2">2</label>
--between---
--after--
</div>
1. <?php echo $form->input('field', array(
2. 'before' => '--before--',
3. 'after' => '--after--',
4. 'between' => '--between---',
5. 'separator' => '--separator--',
6. 'options' => array('1', '2')
7. ));?>
8.
9. Output:
10.
11. <div class="input">
12. --before--
13. <input name="data[User][field]" type="radio" value="1"
id="UserField1" />
14. <label for="UserField1">1</label>
15. --separator--
16. <input name="data[User][field]" type="radio" value="2"
id="UserField2" />
17. <label for="UserField2">2</label>
18. --between---
19. --after--
20. </div>
For date and datetime type elements the 'separator' attribute can be used to change the string
between select elements. Defaults to '-'.
See comments for this section

7.3.3.4 $options[‘options’]
• Edit
• View just this section
• Comments (5)
• History
This key allows you to manually specify options for a select input, or for a radio group. Unless
the ‘type’ is specified as ‘radio’, the FormHelper will assume that the target output is a select
input.
Plain Text View

<?php echo $form->input('field', array('options' => array(1,2,3,4,5))); ?>


1. <?php echo $form->input('field', array('options' => array(1,2,3,4,5)));
?>
Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
</div>
Options can also be supplied as key-value pairs.
Plain Text View

<?php echo $form->input('field', array('options' => array(


'Value 1'=>'Label 1',
'Value 2'=>'Label 2',
'Value 3'=>'Label 3'
))); ?>
1. <?php echo $form->input('field', array('options' => array(
2. 'Value 1'=>'Label 1',
3. 'Value 2'=>'Label 2',
4. 'Value 3'=>'Label 3'
5. ))); ?>
Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
<option value="Value 3">Label 3</option>
</select>
</div>
If you would like to generate a select with optgroups, just pass data in hierarchical format. Works
on multiple checkboxes and radio buttons too, but instead of optgroups wraps elements in
fieldsets.
Plain Text View

<?php echo $form->input('field', array('options' => array(


'Label1' => array(
'Value 1'=>'Label 1',
'Value 2'=>'Label 2'
),
'Label2' => array(
'Value 3'=>'Label 3'
)
))); ?>
1. <?php echo $form->input('field', array('options' => array(
2. 'Label1' => array(
3. 'Value 1'=>'Label 1',
4. 'Value 2'=>'Label 2'
5. ),
6. 'Label2' => array(
7. 'Value 3'=>'Label 3'
8. )
9. ))); ?>
Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<optgroup label="Label1">
<option value="Value 1">Label 1</option>
<option value="Value 2">Label 2</option>
</optgroup>
<optgroup label="Label2">
<option value="Value 3">Label 3</option>
</optgroup>
</select>
</div>
See comments for this section

7.3.3.5 $options[‘multiple’]
• Edit
• View just this section
• Comments (3)
• History
If ‘multiple’ has been set to true for an input that outputs a select, the select will allow multiple
selections. Alternatively set ‘multiple’ to ‘checkbox’ to output a list of related check boxes.
Plain Text View

$form->input('Model.field', array( 'type' => 'select', 'multiple' => true ));


$form->input('Model.field', array( 'type' => 'select', 'multiple' =>
'checkbox' ));
1. $form->input('Model.field', array( 'type' => 'select', 'multiple' =>
true ));
2. $form->input('Model.field', array( 'type' => 'select', 'multiple' =>
'checkbox' ));
See comments for this section
7.3.3.6 $options[‘maxLength’]
• Edit
• View just this section
• Comments (1)
• History
Defines the maximum number of characters allowed in a text input.
See comments for this section

7.3.3.7 $options[‘div’]
• Edit
• View just this section
• Comments (1)
• History
Use this option to set attributes of the input's containing div. Using a string value will set the
div's class name. An array will set the div's attributes to those specified by the array's
keys/values. Alternatively, you can set this key to false to disable the output of the div.
Setting the class name:
Plain Text View

echo $form->input('User.name', array('div' => 'class_name'));


1. echo $form->input('User.name', array('div' => 'class_name'));
Output:
<div class="class_name">
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>
Setting multiple attributes:
Plain Text View

echo $form->input('User.name', array('div' => array('id' => 'mainDiv',


'title' => 'Div Title', 'style' => 'display:block')));
1. echo $form->input('User.name', array('div' => array('id' => 'mainDiv',
'title' => 'Div Title', 'style' => 'display:block')));
Output:
<div class="input text" id="mainDiv" title="Div Title" style="display:block">
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>
Disabling div output:
Plain Text View
<?php echo $form->input('User.name', array('div' => false));?>
1. <?php echo $form->input('User.name', array('div' => false));?>
Output:
<label for="UserName">Name</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
See comments for this section

7.3.3.8 $options[‘label’]
• Edit
• View just this section
• Comments (0)
• History
Set this key to the string you would like to be displayed within the label that usually
accompanies the input.
Plain Text View

<?php echo $form->input( 'User.name', array( 'label' => 'The User


Alias' ) );?>
1. <?php echo $form->input( 'User.name', array( 'label' => 'The User
Alias' ) );?>
Output:
<div class="input">
<label for="UserName">The User Alias</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>
Alternatively, set this key to false to disable the output of the label.
Plain Text View

<?php echo $form->input( 'User.name', array( 'label' => false ) ); ?>


1. <?php echo $form->input( 'User.name', array( 'label' => false ) ); ?>
Output:
<div class="input">
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>
Set this to an array to provide additional options for the label element. If you do this, you can
use a text key in the array to customize the label text.
Plain Text View

<?php echo $form->input( 'User.name', array( 'label' => array('class' =>


'thingy', 'text' => 'The User Alias') ) ); ?>
1. <?php echo $form->input( 'User.name', array( 'label' => array('class'
=> 'thingy', 'text' => 'The User Alias') ) ); ?>
Output:
<div class="input">
<label for="UserName" class="thingy">The User Alias</label>
<input name="data[User][name]" type="text" value="" id="UserName" />
</div>
See comments for this section

7.3.3.9 $options['legend']
• Edit
• View just this section
• Comments (0)
• History
Some inputs like radio buttons will be automatically wrapped in a fieldset with a legend title
derived from the fields name. The title can be overridden with this option. Setting this option to
false will completely eliminate the fieldset.
See comments for this section

7.3.3.10 $options[‘id’]
• Edit
• View just this section
• Comments (0)
• History
Set this key to force the value of the DOM id for the input.
See comments for this section

7.3.3.11 $options['error']
• Edit
• View just this section
• Comments (1)
• History
Using this key allows you to override the default model error messages and can be used, for
example, to set i18n messages. It has a number of suboptions which control the wrapping
element, wrapping element class name, and whether HTML in the error message will be escaped.
To disable error message output set the error key to false.
Plain Text View

$form->input('Model.field', array('error' => false));


1. $form->input('Model.field', array('error' => false));
To modify the wrapping element type and its class, use the following format:
Plain Text View

$form->input('Model.field', array('error' => array('wrap' => 'span', 'class'


=> 'bzzz')));
1. $form->input('Model.field', array('error' => array('wrap' => 'span',
'class' => 'bzzz')));
To prevent HTML being automatically escaped in the error message output, set the escape
suboption to false:
Plain Text View

$form->input('Model.field', array('error' => array('escape' => false)));


1. $form->input('Model.field', array('error' => array('escape' => false)));
To override the model error messages use an associate array with the keyname of the validation
rule:
Plain Text View

$form->input('Model.field', array('error' => array('tooShort' => __('This is


not long enough', true) )));
1. $form->input('Model.field', array('error' => array('tooShort' =>
__('This is not long enough', true) )));
As seen above you can set the error message for each validation rule you have in your models. In
addition you can provide i18n messages for your forms.
See comments for this section

7.3.3.12 $options['default']
• Edit
• View just this section
• Comments (0)
• History
Used to set a default value for the input field. The value is used if the data passed to the form
does not contain a value for the field (or if no data is passed at all).
Example usage:
Plain Text View

<?php
echo $form->input('ingredient', array('default'=>'Sugar'));
?>
1. <?php
2. echo $form->input('ingredient', array('default'=>'Sugar'));
3. ?>
Example with select field (Size "Medium" will be selected as default):
Plain Text View

<?php
$sizes = array('s'=>'Small', 'm'=>'Medium', 'l'=>'Large');
echo $form->input('size', array('options'=>$sizes, 'default'=>'m'));
?>
1. <?php
2. $sizes = array('s'=>'Small', 'm'=>'Medium', 'l'=>'Large');
3. echo $form->input('size', array('options'=>$sizes, 'default'=>'m'));
4. ?>
You cannot use default to check a checkbox - instead you might set the value in $this->data
in your controller, $form->data in your view, or set the input option checked to true.
Date and datetime fields' default values can be set by using the 'selected' key.
See comments for this section

7.3.3.13 $options[‘selected’]
• Edit
• View just this section
• Comments (8)
• History
Used in combination with a select-type input (i.e. For types select, date, time, datetime). Set
‘selected’ to the value of the item you wish to be selected by default when the input is rendered.
Plain Text View

echo $form->input('close_time', array('type' => 'time', 'selected' =>


'13:30:00'));
1. echo $form->input('close_time', array('type' => 'time', 'selected' =>
'13:30:00'));
The selected key for date and datetime inputs may also be a UNIX timestamp.
See comments for this section

7.3.3.14 $options[‘rows’], $options[‘cols’]


• Edit
• View just this section
• Comments (0)
• History
These two keys specify the number of rows and columns in a textarea input.
Plain Text View

echo $form->input('textarea', array('rows' => '5', 'cols' => '5'));


1. echo $form->input('textarea', array('rows' => '5', 'cols' => '5'));
Output:
Plain Text View

<div class="input text">


<label for="FormTextarea">Textarea</label>
<textarea name="data[Form][textarea]" cols="5" rows="5" id="FormTextarea"
>
</textarea>
</div>
1. <div class="input text">
2. <label for="FormTextarea">Textarea</label>
3. <textarea name="data[Form][textarea]" cols="5" rows="5"
id="FormTextarea" >
4. </textarea>
5. </div>
See comments for this section
7.3.3.15 $options[‘empty’]
• Edit
• View just this section
• Comments (0)
• History
If set to true, forces the input to remain empty.
When passed to a select list, this creates a blank option with an empty value in your drop down
list. If you want to have a empty value with text displayed instead of just a blank option, pass in a
string to empty.
Plain Text View

<?php echo $form->input('field', array('options' => array(1,2,3,4,5), 'empty'


=> '(choose one)')); ?>
1. <?php echo $form->input('field', array('options' => array(1,2,3,4,5),
'empty' => '(choose one)')); ?>
Output:
<div class="input">
<label for="UserField">Field</label>
<select name="data[User][field]" id="UserField">
<option value="">(choose one)</option>
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
</select>
</div>
If you need to set the default value in a password field to blank, use 'value' => '' instead.
Options can also supplied as key-value pairs.
See comments for this section

7.3.3.16 $options[‘timeFormat’]
• Edit
• View just this section
• Comments (0)
• History
Used to specify the format of the select inputs for a time-related set of inputs. Valid values
include ‘12’, ‘24’, and ‘none’.
See comments for this section

7.3.3.17 $options[‘dateFormat’]
• Edit
• View just this section
• Comments (0)
• History
Used to specify the format of the select inputs for a date-related set of inputs. Valid values
include ‘DMY’, ‘MDY’, ‘YMD’, and ‘NONE’.
See comments for this section

7.3.3.18 $options['minYear'], $options['maxYear']


• Edit
• View just this section
• Comments (0)
• History
Used in combination with a date/datetime input. Defines the lower and/or upper end of values
shown in the years select field.
See comments for this section

7.3.3.19 $options['interval']
• Edit
• View just this section
• Comments (0)
• History
This option specifies the number of minutes between each option in the minutes select box.
Plain Text View

<?php echo $form->input('Model.time', array('type' => 'time', 'interval' =>


15)); ?>
1. <?php echo $form->input('Model.time', array('type' => 'time',
'interval' => 15)); ?>
Would create 4 options in the minute select. One for each 15 minutes.
See comments for this section
7.3.3.20 $options['class']
• Edit
• View just this section
• Comments (0)
• History
You can set the classname for an input field using $options['class']
Plain Text View

echo $form->input('title', array('class' => 'custom-class'));


1. echo $form->input('title', array('class' => 'custom-class'));
See comments for this section
« Closing the Form | File Fields »

7.3.4 File Fields


• Edit
• Comments (4)
• History
To add a file upload field to a form, you must first make sure that the form enctype is set to
"multipart/form-data", so start off with a create function such as the following.
Plain Text View

echo $form->create('Document', array('enctype' => 'multipart/form-data') );


// OR
echo $form->create('Document', array('type' => 'file'));
1. echo $form->create('Document', array('enctype' => 'multipart/form-
data') );
2. // OR
3. echo $form->create('Document', array('type' => 'file'));
Next add either of the two lines to your form view file.
Plain Text View

echo $form->input('Document.submittedfile', array('between'=>'<br


/>','type'=>'file'));

// or

echo $form->file('Document.submittedfile');
1. echo $form->input('Document.submittedfile', array('between'=>'<br
/>','type'=>'file'));
2. // or
3. echo $form->file('Document.submittedfile');
Due to the limitations of HTML itself, it is not possible to put default values into input fields of
type 'file'. Each time the form is displayed, the value inside will be empty.
Upon submission, file fields provide an expanded data array to the script receiving the form data.
For the example above, the values in the submitted data array would be organized as follows, if
the CakePHP was installed on a Windows server. 'tmp_name' will have a different path in a Unix
environment.
Plain Text View

$this->data['Document']['submittedfile'] = array(
'name' => conference_schedule.pdf
'type' => application/pdf
'tmp_name' => C:/WINDOWS/TEMP/php1EE.tmp
'error' => 0
'size' => 41737
);
1. $this->data['Document']['submittedfile'] = array(
2. 'name' => conference_schedule.pdf
3. 'type' => application/pdf
4. 'tmp_name' => C:/WINDOWS/TEMP/php1EE.tmp
5. 'error' => 0
6. 'size' => 41737
7. );
This array is generated by PHP itself, so for more detail on the way PHP handles data passed via
file fields read the PHP manual section on file uploads.
7.3.4.1 Validating Uploads
• Edit
• View just this section
• Comments (0)
• History
Below is an example validation method you could define in your model to validate whether a file
has been successfully uploaded.
Plain Text View

// Based on comment 8 from: http://bakery.cakephp.org/articles/view/improved-


advance-validation-with-parameters

function isUploadedFile($params){
$val = array_shift($params);
if ((isset($val['error']) && $val['error'] == 0) ||
(!empty( $val['tmp_name']) && $val['tmp_name'] != 'none')) {
return is_uploaded_file($val['tmp_name']);
}
return false;
}
1. // Based on comment 8 from:
http://bakery.cakephp.org/articles/view/improved-advance-validation-
with-parameters
2. function isUploadedFile($params){
3. $val = array_shift($params);
4. if ((isset($val['error']) && $val['error'] == 0) ||
5. (!empty( $val['tmp_name']) && $val['tmp_name'] != 'none')) {
6. return is_uploaded_file($val['tmp_name']);
7. }
8. return false;
9. }
See comments for this section
« $options['class'] | Form Element-Specific Methods »

7.3.5 Form Element-Specific Methods


• Edit
• Comments (4)
• History
The rest of the methods available in the FormHelper are for creating specific form elements.
Many of these methods also make use of a special $options parameter. In this case, however,
$options is used primarily to specify HTML tag attributes (such as the value or DOM id of an
element in the form).
Plain Text View

<?php echo $form->text('username', array('class' => 'users')); ?>


1. <?php echo $form->text('username', array('class' => 'users')); ?>
Will output:

<input name="data[User][username]" type="text" class="users"


id="UserUsername" />

7.3.5.1 checkbox
• Edit
• View just this section
• Comments (0)
• History
checkbox(string $fieldName, array $options)
Creates a checkbox form element. This method also generates an associated hidden form input to
force the submission of data for the specified field.
Plain Text View

<?php echo $form->checkbox('done'); ?>


1. <?php echo $form->checkbox('done'); ?>
Will output:
<input type="hidden" name="data[User][done]" value="0" id="UserDone_" />
<input type="checkbox" name="data[User][done]" value="1" id="UserDone" />
See comments for this section

7.3.5.2 button
• Edit
• View just this section
• Comments (0)
• History
button(string $title, array $options = array())
Creates an HTML button with the specified title and a default type of "button". Setting
$options['type'] will output one of the three possible button types:
1. button: Creates a standard push button (the default).
2. reset: Creates a form reset button.
3. submit: Same as the $form->submit method.
Plain Text View
<?php
echo $form->button('A Button');
echo $form->button('Another Button', array('type'=>'button'));
echo $form->button('Reset the Form', array('type'=>'reset'));
echo $form->button('Submit Form', array('type'=>'submit'));
?>
1. <?php
2. echo $form->button('A Button');
3. echo $form->button('Another Button', array('type'=>'button'));
4. echo $form->button('Reset the Form', array('type'=>'reset'));
5. echo $form->button('Submit Form', array('type'=>'submit'));
6. ?>
Will output:
<input type="button" value="A Button" />
<input type="button" value="Another Button" />
<input type="reset" value="Reset the Form" />
<input type="Submit" value="Submit Form" />
See comments for this section

7.3.5.3 year
• Edit
• View just this section
• Comments (0)
• History
year(string $fieldName, int $minYear, int $maxYear, mixed $selected, array
$attributes, mixed $showEmpty)
Creates a select element populated with the years from $minYear to $maxYear, with the
$selected year selected by default. $selected can either be a four-digit year (e.g. 2004) or
string 'now'. HTML attributes may be supplied in $attributes.
Plain Text View

<?php
echo $form->year('purchased', 2005, 2009);
?>
1. <?php
2. echo $form->year('purchased', 2005, 2009);
3. ?>
Will output:
<select name="data[User][purchased][year]" id="UserPurchasedYear">
<option value=""></option>
<option value="2009">2009</option>
<option value="2008">2008</option>
<option value="2007">2007</option>
<option value="2006">2006</option>
<option value="2005">2005</option>
</select>
If $showEmpty is false, the select will not include an empty option. If $showEmpty is a string, it
will be used as empty option's name.
Plain Text View

<?php
echo $form->year('returned', 2008, 2010, null, null, 'Select a year');
?>
1. <?php
2. echo $form->year('returned', 2008, 2010, null, null, 'Select a year');
3. ?>
Will output:
<select name="data[User][returned][year]" id="UserReturnedYear">
<option value="">Select a year</option>
<option value="2010">2010</option>
<option value="2009">2009</option>
<option value="2008">2008</option>
</select>
See comments for this section

7.3.5.4 month
• Edit
• View just this section
• Comments (0)
• History
month(string $fieldName, mixed $selected, array $attributes, boolean
$showEmpty)
Creates a select element populated with month names.
Plain Text View

<?php
echo $form->month('mob');
?>
1. <?php
2. echo $form->month('mob');
3. ?>
Will output:
<select name="data[User][mob][month]" id="UserMobMonth">
<option value=""></option>
<option value="01">January</option>
<option value="02">February</option>
<option value="03">March</option>
<option value="04">April</option>
<option value="05">May</option>
<option value="06">June</option>
<option value="07">July</option>
<option value="08">August</option>
<option value="09">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
You can pass in your own array of months to be used by setting the 'monthNames' attribute
(CakePHP 1.3 only), or have months displayed as numbers by passing false. (Note: the default
months are internationalized and can be translated using localization.)
Plain Text View

<?php
echo $form->month('mob', null, array('monthNames' => false));
?>
1. <?php
2. echo $form->month('mob', null, array('monthNames' => false));
3. ?>
See comments for this section
7.3.5.5 dateTime
• Edit
• View just this section
• Comments (4)
• History
dateTime(string $fieldName, string $dateFormat = ‘DMY’, $timeFormat = ‘12’,
mixed $selected, array $attributes, boolean $showEmpty)
Creates a set of select inputs for date and time. Valid values for $dateformat are ‘DMY’, ‘MDY’,
‘YMD’ or ‘NONE’. Valid values for $timeFormat are ‘12’, ‘24’, and ‘NONE’.
See comments for this section

7.3.5.6 day
• Edit
• View just this section
• Comments (0)
• History
day(string $fieldName, mixed $selected, array $attributes, boolean $showEmpty)
Creates a select element populated with the (numerical) days of the month.
To create an empty option with prompt text of your choosing (e.g. the first option is 'Day'), you
can supply the text as the final parameter as follows:
Plain Text View

<?php
echo $form->day('created');
?>
1. <?php
2. echo $form->day('created');
3. ?>
Will output:
<select name="data[User][created][day]" id="UserCreatedDay">
<option value=""></option>
<option value="01">1</option>
<option value="02">2</option>
<option value="03">3</option>
...
<option value="31">31</option>
</select>
See comments for this section

7.3.5.7 hour
• Edit
• View just this section
• Comments (0)
• History
hour(string $fieldName, boolean $format24Hours, mixed $selected, array
$attributes, boolean $showEmpty)
Creates a select element populated with the hours of the day.
See comments for this section

7.3.5.8 minute
• Edit
• View just this section
• Comments (0)
• History
minute(string $fieldName, mixed $selected, array $attributes, boolean
$showEmpty)
Creates a select element populated with the minutes of the hour.
See comments for this section

7.3.5.9 meridian
• Edit
• View just this section
• Comments (0)
• History
meridian(string $fieldName, mixed $selected, array $attributes, boolean
$showEmpty)
Creates a select element populated with ‘am’ and ‘pm’.
See comments for this section

7.3.5.10 error
• Edit
• View just this section
• Comments (3)
• History
error(string $fieldName, string $text, array $options)
Shows a validation error message, specified by $text, for the given field, in the event that a
validation error has occurred.
Options:
• 'escape' bool Whether or not to html escape the contents of the error.
• 'wrap' mixed Whether or not the error message should be wrapped in a div. If
a string, will be used as the HTML tag to use.
• 'class' string The classname for the error message
See comments for this section
7.3.5.11 file
• Edit
• View just this section
• Comments (0)
• History
file(string $fieldName, array $options)
Creates a file input.
Plain Text View

<?php
echo $form->create('User',array('type'=>'file'));
echo $form->file('avatar');
?>
1. <?php
2. echo $form->create('User',array('type'=>'file'));
3. echo $form->file('avatar');
4. ?>
Will output:
<form enctype="multipart/form-data" method="post" action="/users/add">
<input name="data[User][avatar]" value="" id="UserAvatar" type="file">
When using $form->file(), remember to set the form encoding-type, by setting the
type option to 'file' in $form->create()

See comments for this section

7.3.5.12 hidden
• Edit
• View just this section
• Comments (5)
• History
hidden(string $fieldName, array $options)
Creates a hidden form input. Example:
Plain Text View

<?php
echo $form->hidden('id');
?>
1. <?php
2. echo $form->hidden('id');
3. ?>
Will output:
<input name="data[User][id]" value="10" id="UserId" type="hidden">
See comments for this section

7.3.5.13 isFieldError
• Edit
• View just this section
• Comments (0)
• History
isFieldError(string $fieldName)
Returns true if the supplied $fieldName has an active validation error.
Plain Text View

<?php
if ($form->isFieldError('gender')){
echo $form->error('gender');
}
?>
1. <?php
2. if ($form->isFieldError('gender')){
3. echo $form->error('gender');
4. }
5. ?>
When using $form->input(), errors are rendered by default.
See comments for this section

7.3.5.14 label
• Edit
• View just this section
• Comments (0)
• History
label(string $fieldName, string $text, array $attributes)
Creates a label tag, populated with $text.
Plain Text View

<?php
echo $form->label('status');
?>
1. <?php
2. echo $form->label('status');
3. ?>
Will output:
<label for="UserStatus">Status</label>
See comments for this section

7.3.5.15 password
• Edit
• View just this section
• Comments (0)
• History
password(string $fieldName, array $options)
Creates a password field.
Plain Text View

<?php
echo $form->password('password');
?>
1. <?php
2. echo $form->password('password');
3. ?>
Will output:
<input name="data[User][password]" value="" id="UserPassword" type="password">
See comments for this section

7.3.5.16 radio
• Edit
• View just this section
• Comments (1)
• History
radio(string $fieldName, array $options, array $attributes)
Creates a radio button input. Use $attributes['value'] to set which value should be selected
default.
Use $attributes['separator'] to specify HTML in between radio buttons (e.g. <br />).
Radio elements are wrapped with a label and fieldset by default. Set $attributes['legend'] to
false to remove them.
Plain Text View

<?php
$options=array('M'=>'Male','F'=>'Female');
$attributes=array('legend'=>false);
echo $form->radio('gender',$options,$attributes);
?>
1. <?php
2. $options=array('M'=>'Male','F'=>'Female');
3. $attributes=array('legend'=>false);
4. echo $form->radio('gender',$options,$attributes);
5. ?>
Will output:
<input name="data[User][gender]" id="UserGender_" value="" type="hidden">
<input name="data[User][gender]" id="UserGenderM" value="M" type="radio">
<label for="UserGenderM">Male</label>
<input name="data[User][gender]" id="UserGenderF" value="F" type="radio">
<label for="UserGenderF">Female</label>
If for some reason you don't want the hidden input, setting $attributes['value'] to a selected
value or boolean false will do just that.
See comments for this section

7.3.5.17 select
• Edit
• View just this section
• Comments (2)
• History
select(string $fieldName, array $options, mixed $selected, array $attributes,
boolean $showEmpty)
Creates a select element, populated with the items in $options, with the option specified by
$selected shown as selected by default. Set $showEmpty to false if you do not want an empty
select option to be displayed.
Plain Text View

<?php
$options=array('M'=>'Male','F'=>'Female');
echo $form->select('gender',$options)
?>
1. <?php
2. $options=array('M'=>'Male','F'=>'Female');
3. echo $form->select('gender',$options)
4. ?>
Will output:
<select name="data[User][gender]" id="UserGender">
<option value=""></option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
See comments for this section

7.3.5.18 submit
• Edit
• View just this section
• Comments (0)
• History
submit(string $caption, array $options)
Creates a submit button with caption $caption. If the supplied $caption is a URL to an image
(it contains a ‘.’ character), the submit button will be rendered as an image.
It is enclosed between div tags by default; you can avoid this by declaring $options['div'] =
false.
Plain Text View

<?php
echo $form->submit();
?>
1. <?php
2. echo $form->submit();
3. ?>
Will output:
<div class="submit"><input value="Submit" type="submit"></div>
You can also pass a relative or absolute url to an image for the caption parameter instead of
caption text.
Plain Text View

<?php
echo $form->submit('ok.png');
?>
1. <?php
2. echo $form->submit('ok.png');
3. ?>
Will output:
<div class="submit"><input type="image" src="/img/ok.png"></div>
See comments for this section

7.3.5.19 text
• Edit
• View just this section
• Comments (0)
• History
text(string $fieldName, array $options)
Creates a text input field.
Plain Text View

<?php
echo $form->text('first_name');
?>
1. <?php
2. echo $form->text('first_name');
3. ?>
Will output:
<input name="data[User][first_name]" value="" id="UserFirstName" type="text">
See comments for this section

7.3.5.20 textarea
• Edit
• View just this section
• Comments (0)
• History
textarea(string $fieldName, array $options)
Creates a textarea input field.
Plain Text View

<?php
echo $form->textarea('notes');
?>
1. <?php
2. echo $form->textarea('notes');
3. ?>
Will output:
<textarea name="data[User][notes]" id="UserNotes"></textarea>
See comments for this section

« Validating Uploads | HTML »

7.4 HTML
• Edit
• Comments (0)
• History
The role of the HtmlHelper in CakePHP is to make HTML-related options easier, faster, and
more resilient to change. Using this helper will enable your application to be more light on its
feet, and more flexible on where it is placed in relation to the root of a domain.
The HtmlHelper's role has changed significantly since CakePHP 1.1. Form related methods have
been deprecated and moved to the new FormHelper. If you're looking for help with HTML
forms, check out the new FormHelper.
Before we look at HtmlHelper's methods, you'll need to know about a few configuration and
usage situations that will help you use this class. First in an effort to assuage those who dislike
short tags (<?= ?>) or many echo() calls in their view code all methods of HtmlHelper are passed
to the output() method. If you wish to enable automatic output of the generated helper HTML
you can simply implement output() in your AppHelper.
Plain Text View

function output($str) {
echo $str;
}
1. function output($str) {
2. echo $str;
3. }
Doing this will remove the need to add echo statements to your view code.
Many HtmlHelper methods also include a $htmlAttributes parameter, that allow you to tack on
any extra attributes on your tags. Here are a few examples of how to use the $htmlAttributes
parameter:
Plain Text View

Desired attributes: <tag class="someClass" />


Array parameter: array('class'=>'someClass')

Desired attributes: <tag name="foo" value="bar" />


Array parameter: array('name' => 'foo', 'value' => 'bar')
1. Desired attributes: <tag class="someClass" />
2. Array parameter: array('class'=>'someClass')
3.
4. Desired attributes: <tag name="foo" value="bar" />
5. Array parameter: array('name' => 'foo', 'value' => 'bar')
The HtmlHelper is available in all views by default. If you're getting an error informing you that
it isn't there, it's usually due to its name being missing from a manually configured $helpers
controller variable.
« Form Element-Specific Methods | Inserting Well-Formatted elements »
7.4.1 Inserting Well-Formatted elements
• Edit
• Comments (2)
• History
The most important task the HtmlHelper accomplishes is creating well formed markup. Don't be
afraid to use it often - you can cache views in CakePHP in order to save some CPU cycles when
views are being rendered and delivered. This section will cover some of the methods of the
HtmlHelper and how to use them.
7.4.1.1 charset
• Edit
• View just this section
• Comments (0)
• History
charset(string $charset=null)
Used to create a meta tag specifying the document's character. Defaults to UTF-8.
Plain Text View

<?php echo $html->charset(); ?>


1. <?php echo $html->charset(); ?>
Will output:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Alternatively,
Plain Text View

<?php echo $html->charset('ISO-8859-1'); ?>


1. <?php echo $html->charset('ISO-8859-1'); ?>
Will output:
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
See comments for this section

7.4.1.2 css
• Edit
• View just this section
• Comments (2)
• History
css(mixed $path, string $rel = null, array $htmlAttributes = array(), boolean
$inline = true)
Creates a link(s) to a CSS style-sheet. If $inline is set to false, the link tags are added to the
$scripts_for_layout variable which you can print inside the head tag of the document.
This method of CSS inclusion assumes that the CSS file specified resides inside the
/app/webroot/css directory.
Plain Text View

<?php echo $html->css('forms'); ?>


1. <?php echo $html->css('forms'); ?>
Will output:
<link rel="stylesheet" type="text/css" href="/css/forms.css" />
The first parameter can be an array to include multiple files.
Plain Text View

<?php echo $html->css(array('forms','tables','menu')); ?>


1. <?php echo $html->css(array('forms','tables','menu')); ?>
Will output:
<link rel="stylesheet" type="text/css" href="/css/forms.css" />
<link rel="stylesheet" type="text/css" href="/css/tables.css" />
<link rel="stylesheet" type="text/css" href="/css/menu.css" />
See comments for this section

7.4.1.3 meta
• Edit
• View just this section
• Comments (0)
• History
meta(string $type, string $url = null, array $attributes = array(), boolean
$inline = true)
This method is handy for linking to external resources like RSS/Atom feeds and favicons. Like
css(), you can specify whether or not you'd like this tag to appear inline or in the head tag using
the fourth parameter.
If you set the "type" attribute using the $htmlAttributes parameter, CakePHP contains a few
shortcuts:
typ translated
e value

html text/html

application/rss+x
rss
ml
typ translated
e value

ato application/atom
m +xml

icon image/x-icon

Plain Text View

<?php echo $html->meta(


'favicon.ico',
'/favicon.ico',
array('type' => 'icon')
);?> //Output (line breaks added) </p>
<link
href="http://example.com/favicon.ico"
title="favicon.ico" type="image/x-icon"
rel="alternate"
/>

<?php echo $html->meta(


'Comments',
'/comments/index.rss',
array('type' => 'rss'));
?>

//Output (line breaks added)


<link
href="http://example.com/comments/index.rss"
title="Comments"
type="application/rss+xml"
rel="alternate"
/>
1. <?php echo $html->meta(
2. 'favicon.ico',
3. '/favicon.ico',
4. array('type' => 'icon')
5. );?> //Output (line breaks added) </p>
6. <link
7. href="http://example.com/favicon.ico"
8. title="favicon.ico" type="image/x-icon"
9. rel="alternate"
10. />
11.
12. <?php echo $html->meta(
13. 'Comments',
14. '/comments/index.rss',
15. array('type' => 'rss'));
16. ?>
17.
18. //Output (line breaks added)
19. <link
20. href="http://example.com/comments/index.rss"
21. title="Comments"
22. type="application/rss+xml"
23. rel="alternate"
24. />
This method can also be used to add the meta keywords and descriptions. Example:
Plain Text View

<?php echo $html->meta(


'keywords',
'enter any meta keyword here'
);?>
//Output <meta name="keywords" content="enter any meta keyword here"/>
//

<?php echo $html->meta(


'description',
'enter any meta description here'
);?>

//Output <meta name="description" content="enter any meta description here"/>


1. <?php echo $html->meta(
2. 'keywords',
3. 'enter any meta keyword here'
4. );?>
5. //Output <meta name="keywords" content="enter any meta keyword here"/>
6. //
7. <?php echo $html->meta(
8. 'description',
9. 'enter any meta description here'
10. );?>
11. //Output <meta name="description" content="enter any meta description
here"/>
If you want to add a custom meta tag then the first parameter should be set to an array. To output
a robots noindex tag use the following code:
Plain Text View

echo $html->meta(array('name' => 'robots', 'content' => 'noindex'));


1. echo $html->meta(array('name' => 'robots', 'content' => 'noindex'));
See comments for this section
7.4.1.4 docType
• Edit
• View just this section
• Comments (0)
• History
docType(string $type = 'xhtml-strict')
Returns a (X)HTML doctype tag. Supply the doctype according to the following table:
translated
type
value

html text/html

html4-
HTML4 Strict
strict

html4- HTML4
trans Transitional

html4-
HTML4 Frameset
frame

xhtml-
XHTML1 Strict
strict

xhtml- XHTML1
trans Transitional

xhtml- XHTML1
frame Frameset

xhtml11 XHTML 1.1

Plain Text View

<?php echo $html->docType(); ?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<?php echo $html->docType('html4-trans'); ?>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
1. <?php echo $html->docType(); ?>
2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3. <?php echo $html->docType('html4-trans'); ?>
4. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
See comments for this section
7.4.1.5 style
• Edit
• View just this section
• Comments (0)
• History
style(array $data, boolean $inline = true)
Builds CSS style definitions based on the keys and values of the array passed to the method.
Especially handy if your CSS file is dynamic.
Plain Text View

<?php echo $html->style(array(


'background' => '#633',
'border-bottom' => '1px solid #000',
'padding' => '10px'
)); ?>
1. <?php echo $html->style(array(
2. 'background' => '#633',
3. 'border-bottom' => '1px solid #000',
4. 'padding' => '10px'
5. )); ?>
Will output:
background:#633;
border-bottom:1px solid #000;
padding:10px;
See comments for this section

7.4.1.6 image
• Edit
• View just this section
• Comments (1)
• History
image(string $path, array $htmlAttributes = array())
Creates a formatted image tag. The path supplied should be relative to /app/webroot/img/.
Plain Text View
<?php echo $html->image('cake_logo.png', array('alt' => 'CakePHP'))?>
1. <?php echo $html->image('cake_logo.png', array('alt' => 'CakePHP'))?>
Will output:
<img src="/img/cake_logo.png" alt="CakePHP" />
To create an image link specify the link destination using the url option in $htmlAttributes.
Plain Text View

<?php echo $html->image("recipes/6.jpg", array(


"alt" => "Brownies",
'url' => array('controller' => 'recipes', 'action' => 'view', 6)
)); ?>
1. <?php echo $html->image("recipes/6.jpg", array(
2. "alt" => "Brownies",
3. 'url' => array('controller' => 'recipes', 'action' => 'view', 6)
4. )); ?>
Will output:
<a href="/recipes/view/6">
<img src="/img/recipes/6.jpg" alt="Brownies" />
</a>
You can also use this alternate method to create an image link, by assigning the image to a
variable (e.g. $image), and passing it to $html->link() as the first argument:
Plain Text View

<?php
$image = $html->image('recipes/6.jpg', array(
'alt' => 'Brownies',
));

//$image is passed as the first argument instead of link text


echo $html->link($image, array(
'controller' => 'recipies',
'action' => 'view',
6
),
array(
'escape' => false //important so htmlHelper doesn't escape
you image link
)
);
?>
1. <?php
2. $image = $html->image('recipes/6.jpg', array(
3. 'alt' => 'Brownies',
4. ));
5. //$image is passed as the first argument instead of link text
6. echo $html->link($image, array(
7. 'controller' => 'recipies',
8. 'action' => 'view',
9. 6
10. ),
11. array(
12. 'escape' => false //important so htmlHelper doesn't escape you image
link
13. )
14. );
15. ?>
This is useful if you want to keep your link and image a bit more separate, or if you want to
sneak some markup into your link. Be sure to pass 'escape' => false in the options array for
$html->link($string, $url, $options) to prevent htmlHelper from escaping the code.
See comments for this section

7.4.1.7 link
• Edit
• View just this section
• Comments (2)
• History
link(string $title, mixed $url = null, array $htmlAttributes = array(),
string $confirmMessage = false, boolean $escapeTitle = true)
General purpose method for creating HTML links. Use $htmlAttributes to specify attributes
for the element.
Plain Text View

<?php echo $html->link('Enter', '/pages/home',


array('class'=>'button','target'=>'_blank')); ?>
1. <?php echo $html->link('Enter', '/pages/home',
array('class'=>'button','target'=>'_blank')); ?>
Will output:

<a href="/pages/home" class="button" target="_blank">Enter</a>


Specify $confirmMessage to display a javascript confirm() dialog.
Plain Text View

<?php echo $html->link(


'Delete',
array('controller'=>'recipes', 'action'=>'delete', 6),
array(),
"Are you sure you wish to delete this recipe?"
);?>
1. <?php echo $html->link(
2. 'Delete',
3. array('controller'=>'recipes', 'action'=>'delete', 6),
4. array(),
5. "Are you sure you wish to delete this recipe?"
6. );?>
Will output:

<a href="/recipes/delete/6" onclick="return confirm('Are you sure you wish to


delete this recipe?');">Delete</a>
Query strings can also be created with link().
Plain Text View

<?php echo $html->link('View image', array(


'controller' => 'images',
'action' => 'view',
1,
'?' => array( 'height' => 400, 'width' => 500))
);
1. <?php echo $html->link('View image', array(
2. 'controller' => 'images',
3. 'action' => 'view',
4. 1,
5. '?' => array( 'height' => 400, 'width' => 500))
6. );
Will output:

<a href="/images/view/1?height=400&width=500">View image</a>


HTML special characters in $title will be converted to HTML entities. To disable this
conversion, set the escape option to false in the $htmlAttributes, or set $escapeTitle to false.
Plain Text View

<?php
echo $html->link(
$html->image("recipes/6.jpg", array("alt" => "Brownies")),
"recipes/view/6",
array('escape'=>false)
);

echo $html->link(
$html->image("recipes/6.jpg", array("alt" => "Brownies")),
"recipes/view/6",
null, null, false
);
?>
1. <?php
2. echo $html->link(
3. $html->image("recipes/6.jpg", array("alt" => "Brownies")),
4. "recipes/view/6",
5. array('escape'=>false)
6. );
7. echo $html->link(
8. $html->image("recipes/6.jpg", array("alt" => "Brownies")),
9. "recipes/view/6",
10. null, null, false
11. );
12. ?>
Both will output:
<a href="/recipes/view/6">
<img src="/img/recipes/6.jpg" alt="Brownies" />
</a>

Also check HtmlHelper::url method for more examples of different types of urls.
See comments for this section

7.4.1.8 tag
• Edit
• View just this section
• Comments (0)
• History
tag(string $tag, string $text, array $htmlAttributes, boolean $escape = false)
Returns text wrapped in a specified tag. If no text is specified then only the opening <tag> is
returned.
Plain Text View

<?php echo $html->tag('span', 'Hello World.', array('class' => 'welcome'));?>

//Output
<span class="welcome">Hello World</span>

//No text specified.


<?php echo $html->tag('span', null, array('class' => 'welcome'));?>

//Output
<span class="welcome">
1. <?php echo $html->tag('span', 'Hello World.', array('class' =>
'welcome'));?>
2.
3. //Output
4. <span class="welcome">Hello World</span>
5.
6. //No text specified.
7. <?php echo $html->tag('span', null, array('class' => 'welcome'));?>
8.
9. //Output
10. <span class="welcome">
See comments for this section
7.4.1.9 div
• Edit
• View just this section
• Comments (18)
• History
div(string $class, string $text, array $htmlAttributes, boolean $escape =
false)
Used for creating div-wrapped sections of markup. The first parameter specifies a CSS class, and
the second is used to supply the text to be wrapped by div tags. If the last parameter has been set
to true, $text will be printed HTML-escaped.
If no text is specified, only an opening div tag is returned.
Plain Text View

<?php echo $html->div('error', 'Please enter your credit card number.');?>

//Output
<div class="error">Please enter your credit card number.</div>
1. <?php echo $html->div('error', 'Please enter your credit card
number.');?>
2.
3. //Output
4. <div class="error">Please enter your credit card number.</div>
See comments for this section
7.4.1.10 para
• Edit
• View just this section
• Comments (0)
• History
para(string $class, string $text, array $htmlAttributes, boolean $escape =
false)
Returns a text wrapped in a CSS-classed <p> tag. If no text is supplied, only a starting <p> tag is
returned.
Plain Text View

<?php echo $html->para(null, 'Hello World.');?>

//Output
<p>Hello World.</p>
1. <?php echo $html->para(null, 'Hello World.');?>
2.
3. //Output
4. <p>Hello World.</p>
See comments for this section
7.4.1.11 tableHeaders
• Edit
• View just this section
• Comments (0)
• History
tableHeaders(array $names, array $trOptions = null, array $thOptions = null)
Creates a row of table header cells to be placed inside of <table> tags.
Plain Text View

<?php echo $html->tableHeaders(array('Date','Title','Active'));?> //Output


<tr><th>Date</th><th>Title</th><th>Active</th></tr>

<?php echo $html->tableHeaders(


array('Date','Title','Active'),
array('class' => 'status'),
array('class' => 'product_table')
);?>

//Output
<tr class="status">
<th class="product_table">Date</th>
<th class="product_table">Title</th>
<th class="product_table">Active</th>
</tr>
1. <?php echo $html->tableHeaders(array('Date','Title','Active'));?>
//Output
2. <tr><th>Date</th><th>Title</th><th>Active</th></tr>
3.
4. <?php echo $html->tableHeaders(
5. array('Date','Title','Active'),
6. array('class' => 'status'),
7. array('class' => 'product_table')
8. );?>
9.
10. //Output
11. <tr class="status">
12. <th class="product_table">Date</th>
13. <th class="product_table">Title</th>
14. <th class="product_table">Active</th>
15. </tr>
See comments for this section
7.4.1.12 tableCells
• Edit
• View just this section
• Comments (1)
• History
tableCells(array $data, array $oddTrOptions = null, array $evenTrOptions =
null, $useCount = false, $continueOddEven = true)
Creates table cells, in rows, assigning <tr> attributes differently for odd- and even-numbered
rows. Wrap a single table cell within an array() for specific <td>-attributes.
Plain Text View

<?php echo $html->tableCells(array(


array('Jul 7th, 2007', 'Best Brownies', 'Yes'),
array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
array('Aug 1st, 2006', 'Anti-Java Cake', 'No'),
));
?>

//Output
<tr><td>Jul 7th, 2007</td><td>Best Brownies</td><td>Yes</td></tr>
<tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
<tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td>No</td></tr>

<?php echo $html->tableCells(array(


array('Jul 7th, 2007', array('Best Brownies',
array('class'=>'highlight')) , 'Yes'),
array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
array('Aug 1st, 2006', 'Anti-Java Cake', array('No',
array('id'=>'special'))),
));
?>

//Output
<tr><td>Jul 7th, 2007</td><td class="highlight">Best
Brownies</td><td>Yes</td></tr>
<tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
<tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td id="special">No</td></tr>

<?php echo $html->tableCells(


array(
array('Red', 'Apple'),
array('Orange', 'Orange'),
array('Yellow', 'Banana'),
),
array('class' => 'darker')
);
?>

//Output
<tr class="darker"><td>Red</td><td>Apple</td></tr>
<tr><td>Orange</td><td>Orange</td></tr>
<tr class="darker"><td>Yellow</td><td>Banana</td></tr>
1. <?php echo $html->tableCells(array(
2. array('Jul 7th, 2007', 'Best Brownies', 'Yes'),
3. array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
4. array('Aug 1st, 2006', 'Anti-Java Cake', 'No'),
5. ));
6. ?>
7.
8. //Output
9. <tr><td>Jul 7th, 2007</td><td>Best Brownies</td><td>Yes</td></tr>
10. <tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
11. <tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td>No</td></tr>
12.
13. <?php echo $html->tableCells(array(
14. array('Jul 7th, 2007', array('Best Brownies',
array('class'=>'highlight')) , 'Yes'),
15. array('Jun 21st, 2007', 'Smart Cookies', 'Yes'),
16. array('Aug 1st, 2006', 'Anti-Java Cake', array('No',
array('id'=>'special'))),
17. ));
18. ?>
19.
20. //Output
21. <tr><td>Jul 7th, 2007</td><td class="highlight">Best
Brownies</td><td>Yes</td></tr>
22. <tr><td>Jun 21st, 2007</td><td>Smart Cookies</td><td>Yes</td></tr>
23. <tr><td>Aug 1st, 2006</td><td>Anti-Java Cake</td><td
id="special">No</td></tr>
24.
25. <?php echo $html->tableCells(
26. array(
27. array('Red', 'Apple'),
28. array('Orange', 'Orange'),
29. array('Yellow', 'Banana'),
30. ),
31. array('class' => 'darker')
32. );
33. ?>
34.
35. //Output
36. <tr class="darker"><td>Red</td><td>Apple</td></tr>
37. <tr><td>Orange</td><td>Orange</td></tr>
38. <tr class="darker"><td>Yellow</td><td>Banana</td></tr>
See comments for this section
7.4.1.13 url
• Edit
• View just this section
• Comments (0)
• History
url(mixed $url = NULL, boolean $full = false)
Returns an URL pointing to a combination of controller and action. If $url is empty, it returns the
REQUEST_URI, otherwise it generates the url for the controller and action combo. If full is true,
the full base URL will be prepended to the result.
Plain Text View

<?php echo $html->url(array(


"controller" => "posts",
"action" => "view",
"bar"));?>

// Output
/posts/view/bar
1. <?php echo $html->url(array(
2. "controller" => "posts",
3. "action" => "view",
4. "bar"));?>
5.
6. // Output
7. /posts/view/bar
Here are a few more usage examples:
URL with named parameters
Plain Text View

<?php echo $html->url(array(


"controller" => "posts",
"action" => "view",
"foo" => "bar"));
?>

// Output
/posts/view/foo:bar
1. <?php echo $html->url(array(
2. "controller" => "posts",
3. "action" => "view",
4. "foo" => "bar"));
5. ?>
6.
7. // Output
8. /posts/view/foo:bar

URL with extension


Plain Text View

<?php echo $html->url(array(


"controller" => "posts",
"action" => "list",
"ext" => "rss"));
?>

// Output
/posts/list.rss
1. <?php echo $html->url(array(
2. "controller" => "posts",
3. "action" => "list",
4. "ext" => "rss"));
5. ?>
6.
7. // Output
8. /posts/list.rss

URL (starting with '/') with the full base URL prepended.
Plain Text View

<?php echo $html->url('/posts', true); ?>

//Output
http://somedomain.com/posts
1. <?php echo $html->url('/posts', true); ?>
2.
3. //Output
4. http://somedomain.com/posts

URL with GET params and named anchor


Plain Text View

<?php echo $html->url(array(


"controller" => "posts",
"action" => "search",
"?" => array("foo" => "bar"),
"#" => "first"));
?>

//Output
/posts/search?foo=bar#first
1. <?php echo $html->url(array(
2. "controller" => "posts",
3. "action" => "search",
4. "?" => array("foo" => "bar"),
5. "#" => "first"));
6. ?>
7.
8. //Output
9. /posts/search?foo=bar#first

For further information check Router::url in the API.


See comments for this section
« HTML | Changing the tags output by HtmlHelper »

7.4.2 Changing the tags output by HtmlHelper


• Edit
• Comments (0)
• History
The built in tag sets for HtmlHelper are XHTML compliant, however if you need to generate
HTML for HTML4 you will need to create and load a new tags config file containing the tags
you'd like to use. To change the tags used create app/config/tags.php containing:
Plain Text View

$tags = array(
'metalink' => '<link href="%s"%s >',
'input' => '<input name="%s" %s >',
//...
);
1. $tags = array(
2. 'metalink' => '<link href="%s"%s >',
3. 'input' => '<input name="%s" %s >',
4. //...
5. );
You can then load this tag set by calling $html->loadConfig('tags');
« url | Javascript »

7.5.1 Methods
• Edit
• Comments (2)
• History
codeBlock($script, $options =
array('allowCache'=>true,'safe'=>true,'inline'=>true), $safe)
• string $script - The JavaScript to be wrapped in SCRIPT tags
• array $options - Set of options:
○ allowCache: boolean, designates whether this block is cacheable using
the current cache settings.
○ safe: boolean, whether this block should be wrapped in CDATA tags.
Defaults to helper's object configuration.
○ inline: whether the block should be printed inline, or written to cached
for later output (i.e. $scripts_for_layout).
• boolean $safe - DEPRECATED. Use $options['safe'] instead
codeBlock returns a formatted script element containing $script. But can also return null if
Javascript helper is set to cache events. See JavascriptHelper::cacheEvents(). And can write in
$scripts_for_layout if you set $options['inline'] to false.
blockEnd()
Ends a block of cached Javascript. Can return either a end script tag, or empties the buffer,
adding the contents to the cachedEvents array. Its return value depends on the cache settings. See
JavascriptHelper::cacheEvents()
link($url, $inline = true)
• mixed $url - String URL to JavaScript file, or an array of URLs.
• boolean $inline If true, the <script> tag will be printed inline, otherwise it will
be printed in $scripts_for_layout
Creates a javascript link to a single or many javascript files. Can output inline or in
$scripts_for_layout.
If the filename is prefixed with "/", the path will be relative to the base path of your application.
Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
escapeString($string)
• string $script - String that needs to get escaped.
Escape a string to be JavaScript friendly. Allowing it to safely be used in javascript blocks.
The characters that are escaped are:
• "\r\n" => '\n'
• "\r" => '\n'
• "\n" => '\n'
• '"' => '\"'
• "'" => "\\'"
event($object, $event, $observer, $options)
• string $object - DOM Object to be observed.
• string $event - type of event to observe ie 'click', 'over'.
• string $observer - Javascript function to call when event occurs.
• array $options - Set options: useCapture, allowCache, safe
○ boolean $options['useCapture'] - Whether to fire the event in the
capture or bubble phase of event handling. Defaults false
○ boolean $options['allowCache'] - See JavascriptHelper::cacheEvents()
○ boolean $options['safe'] - Indicates whether <script /> blocks should
be written 'safely,' i.e. wrapped in CDATA blocks
Attach a javascript event handler specified by $event to an element DOM element specified by
$object. Object does not have to be an ID reference it can refer to any valid javascript object or
CSS selectors. If a CSS selector is used the event handler is cached and should be retrieved with
JavascriptHelper::getCache(). This method requires the Prototype library.
cacheEvents($file, $all)
• boolean $file - If true, code will be written to a file
• boolean $all - If true, all code written with JavascriptHelper will be sent to a
file
Allows you to control how the JavaScript Helper caches event code generated by event(). If $all
is set to true, all code generated by the helper is cached and can be retrieved with getCache() or
written to file or page output with writeCache().
getCache($clear)
• boolean $clear - If set to true the cached javascript is cleared. Defaults to
true.
Gets (and clears) the current JavaScript event cache
writeEvents($inline)
• boolean $inline - If true, returns JavaScript event code. Otherwise it is added
to the output of $scripts_for_layout in the layout.
Returns cached javascript code. If $file was set to true with cacheEvents(), code is cached to a
file and a script link to the cached events file is returned. If inline is true, the event code is
returned inline. Else it is added to the $scripts_for_layout for the page.
includeScript($script)
• string $script - File name of script to include.
Includes the named $script. If $script is left blank the helper will include every script in your
app/webroot/js directory. Includes the contents of each file inline. To create a script tag with an
src attribute use link().
object($data, $options)
• array $data - Data to be converted
• array $options - Set of options: block, prefix, postfix, stringKeys, quoteKeys, q
○ boolean $options['block'] - Wraps return value in a <script /> block if
true. Defaults to false.
○ string $options['prefix'] - Prepends the string to the returned data.
○ string $options['postfix'] - Appends the string to the returned data.
○ array $options['stringKeys'] - A list of array keys to be treated as a
string.
○ boolean $options['quoteKeys'] - If false, treats $stringKey as a list of
keys *not* to be quoted. Defaults to true.
○ string $options['q'] - The type of quote to use.
Generates a JavaScript object in JavaScript Object Notation (JSON) from $data array.
« Javascript | Number »
7.6.1 currency
• Edit
• Comments (0)
• History
currency(mixed $number, string $currency= 'USD')
This method is used to display a number in common currency formats (EUR,GBP,USD). Usage
in a view looks like:
Plain Text View

<?php echo $number->currency($number,$currency); ?>


1. <?php echo $number->currency($number,$currency); ?>
The first parameter, $number, should be a floating point number that represents the amount of
money you are expressing. The second parameter is used to choose a predefined currency
formatting scheme:
$curre 1234.56, formatted by
ncy currency type

EUR € 1.236,33

GBP £ 1,236.33

USD $ 1,236.33

HTML entities are outputted as currency symbols where needed.


If a non-recognized $currency value is supplied, it is prepended to a USD formatted number. For
example:
Plain Text View

<?php echo $number->currency('1234.56', 'FOO'); ?>

//Outputs:
FOO 1,234.56
1. <?php echo $number->currency('1234.56', 'FOO'); ?>
2.
3. //Outputs:
4. FOO 1,234.56
« Number | precision »
7.6.2 precision
• Edit
• Comments (0)
• History
precision (mixed $number, int $precision = 3)
This method displays a number with the specified amount of precision (decimal places). It will
round in order to maintain the level of precision defined.
Plain Text View

<?php echo $number->precision(456.91873645, 2 ); ?>

//Outputs:
456.92
1. <?php echo $number->precision(456.91873645, 2 ); ?>
2.
3. //Outputs:
4. 456.92
« currency | toPercentage »

7.6.3 toPercentage
• Edit
• Comments (0)
• History
toPercentage(mixed $number, int $precision = 2)
Like precision(), this method formats a number according to the supplied precision (where
numbers are rounded to meet the given precision). This method also expresses the number as a
percentage and prepends the output with a percent sign.
Plain Text View

<?php echo $number->toPercentage(45.691873645); ?>

//Outputs:
45.69%
1. <?php echo $number->toPercentage(45.691873645); ?>
2.
3. //Outputs:
4. 45.69%
« precision | toReadableSize »
7.6.4 toReadableSize
• Edit
• Comments (0)
• History
toReadableSize(string $data_size)
This method formats data sizes in human readable forms. It provides a shortcut way to convert
bytes to KB, MB, GB, and TB. The size is displayed with a two-digit precision level, according
to the size of data supplied (i.e. higher sizes are expressed in larger terms):
Plain Text View

echo $number->toReadableSize(0); // 0 Bytes


echo $number->toReadableSize(1024); // 1 KB
echo $number->toReadableSize(1321205.76); // 1.26 MB
echo $number->toReadableSize(5368709120); // 5.00 GB
1. echo $number->toReadableSize(0); // 0 Bytes
2. echo $number->toReadableSize(1024); // 1 KB
3. echo $number->toReadableSize(1321205.76); // 1.26 MB
4. echo $number->toReadableSize(5368709120); // 5.00 GB
« toPercentage | format »

7.6.5 format
• Edit
• Comments (0)
• History
format (mixed $number, mixed $options=false)
This method gives you much more control over the formatting of numbers for use in your views
(and is used as the main method by most of the other NumberHelper methods). Using this
method might looks like:
Plain Text View

$number->format($number, $options);
1. $number->format($number, $options);
The $number parameter is the number that you are planning on formatting for output. With no
$options supplied, the number 1236.334 would output as 1,236. Note that the default precision is
zero decimal places.
The $options parameter is where the real magic for this method resides.
• If you pass an integer then this becomes the amount of precision or places
for the function.
• If you pass an associated array, you can use the following keys:
○ places (integer): the amount of desired precision
○ before (string): to be put before the outputted number
○ escape (boolean): if you want the value in before to be escaped
○ decimals (string): used to delimit the decimal places in a number
○ thousands (string): used to mark off thousand, millions, … places
Plain Text View
echo $number->format('123456.7890', array(
'places' => 2,
'before' => '¥ ',
'escape' => false,
'decimals' => '.',
'thousands' => ','
));
// output '¥ 123,456.79'
1. echo $number->format('123456.7890', array(
2. 'places' => 2,
3. 'before' => '¥ ',
4. 'escape' => false,
5. 'decimals' => '.',
6. 'thousands' => ','
7. ));
8. // output '¥ 123,456.79'
« toReadableSize | Paginator »

7.7.1 Methods
• Edit
• Comments (1)
• History
options($options = array())
• mixed options() Default options for pagination links. If a string is supplied - it
is used as the DOM id element to update. See #options for list of keys.
options() sets all the options for the Paginator Helper. Supported options are:
format

Format of the counter. Supported formats are 'range' and 'pages' and custom which is the default.
In the default mode the supplied string is parsed and tokens are replaced with actual values. The
available tokens are:
• %page% - the current page displayed.
• %pages% - total number of pages.
• %current% - current number of records being shown.
• %count% - the total number of records in the result set.
• %start% - number of the first record being displayed.
• %end% - number of the last record being displayed.
Now that you know the available tokens you can use the counter() method to display all sorts of
information about the returned results, for example:
Plain Text View

echo $paginator->counter(array(
'format' => 'Page %page% of %pages%,
showing %current% records out of %count% total,
starting on record %start%, ending on %end%'
));

1. echo $paginator->counter(array(
2. 'format' => 'Page %page% of %pages%,
3. showing %current% records out of %count% total,
4. starting on record %start%, ending on %end%'
5. ));
separator
The separator between the actual page and the number of pages. Defaults to ' of '. This is used in
conjunction with format = 'pages'
url

The url of the paginating action. url has a few sub options as well
• sort - the key that the records are sorted by
• direction - The direction of the sorting. Defaults to 'ASC'
• page - The page number to display
model
The name of the model being paginated.
escape
Defines if the title field for links should be HTML escaped. Defaults to true.
update

The DOM id of the element to update with the results of AJAX pagination calls. If not specified,
regular links will be created.
indicator

DOM id of the element that will be shown as a loading or working indicator while doing AJAX
requests.
link($title, $url = array(), $options = array())

• string $title - Title for the link.


• mixed $url Url for the action. See Router::url()
• array $options Options for the link. See options() for list of keys.
Creates a regular or AJAX link with pagination parameters
Plain Text View

echo $paginator->link('Sort by title on page 5',


array('sort' => 'title', 'page' => 5, 'direction' => 'desc'));
1. echo $paginator->link('Sort by title on page 5',
2. array('sort' => 'title', 'page' => 5, 'direction' => 'desc'));
If created in the view for /posts/index Would create a link pointing at
'/posts/index/page:5/sort:title/direction:desc'
« Paginator | RSS »

7.8.1 Creating an RSS feed with the RssHelper


• Edit
• Comments (4)
• History
This example assumes you have a Posts Controller and Post Model already created and want to
make an alternative view for RSS.
Creating an xml/rss version of posts/index is a snap with CakePHP 1.2. After a few simple steps
you can simply append the desired extension .rss to posts/index making your URL
posts/index.rss. Before we jump too far ahead trying to get our webservice up and running we
need to do a few things. First parseExtensions needs to be activated, this is done in
app/config/routes.php
Plain Text View

Router::parseExtensions('rss');
1. Router::parseExtensions('rss');
In the call above we’ve activated the .rss extension. When using Router::parseExtensions() you
can pass as many arguments or extensions as you want. This will activate each
extension/content-type for use in your application. Now when the address posts/index.rss is
requested you will get an xml version of your posts/index. However, first we need to edit the
controller to add in the rss-specific code.
7.8.1.1 Controller Code
• Edit
• View just this section
• Comments (2)
• History
It is a good idea to add RequestHandler to your PostsController's $components array. This will
allow a lot of automagic to occur.
Plain Text View

var $components = array('RequestHandler');


1. var $components = array('RequestHandler');
Before we can make an RSS version of our posts/index we need to get a few things in order. It
may be tempting to put the channel metadata in the controller action and pass it to your view
using the Controller::set() method but this is inappropriate. That information can also go in the
view. That will come later though, for now if you have a different set of logic for the data used to
make the RSS feed and the data for the html view you can use the RequestHandler::isRss()
method, otherwise your controller can stay the same.
Plain Text View

// Modify the Posts Controller action that corresponds to


// the action which deliver the rss feed, which is the
// index action in our example

public function index(){


if( $this->RequestHandler->isRss() ){
$posts = $this->Post->find('all', array('limit' => 20, 'order' =>
'Post.created DESC'));
$this->set(compact('posts'));
} else {
// this is not an Rss request, so deliver
// data used by website's interface
$this->paginate['Post'] = array('order' => 'Post.created DESC',
'limit' => 10);

$posts = $this->paginate();
$this->set(compact('posts'));
}
}
1. // Modify the Posts Controller action that corresponds to
2. // the action which deliver the rss feed, which is the
3. // index action in our example
4. public function index(){
5. if( $this->RequestHandler->isRss() ){
6. $posts = $this->Post->find('all', array('limit' => 20, 'order' =>
'Post.created DESC'));
7. $this->set(compact('posts'));
8. } else {
9. // this is not an Rss request, so deliver
10. // data used by website's interface
11. $this->paginate['Post'] = array('order' => 'Post.created DESC', 'limit'
=> 10);
12.
13. $posts = $this->paginate();
14. $this->set(compact('posts'));
15. }
16. }
With all the View variables set we need to create an rss layout.
See comments for this section

7.8.1.1.1 Layout
• Edit
• View just this section
• Comments (0)
• History
An Rss layout is very simple, put the following contents in
app/views/layouts/rss/default.ctp:
Plain Text View

echo $rss->header();
if (!isset($documentData)) {
$documentData = array();
}
if (!isset($channelData)) {
$channelData = array();
}
if (!isset($channelData['title'])) {
$channelData['title'] = $title_for_layout;
}
$channel = $rss->channel(array(), $channelData, $content_for_layout);
echo $rss->document($documentData,$channel);
1. echo $rss->header();
2. if (!isset($documentData)) {
3. $documentData = array();
4. }
5. if (!isset($channelData)) {
6. $channelData = array();
7. }
8. if (!isset($channelData['title'])) {
9. $channelData['title'] = $title_for_layout;
10. }
11. $channel = $rss->channel(array(), $channelData, $content_for_layout);
12. echo $rss->document($documentData,$channel);
It doesn't look like much but thanks to the power in the RssHelper its doing a lot of lifting for us.
We haven't set $documentData or $channelData in the controller, however in CakePHP 1.2 your
views can pass variables back to the layout. Which is where our $channelData array will come
from setting all of the meta data for our feed.
Next up is view file for my posts/index. Much like the layout file we created, we need to create a
views/posts/rss/ directory and create a new index.ctp inside that folder. The contents of the file
are below.
See comments for this section

7.8.1.1.2 View
• Edit
• View just this section
• Comments (3)
• History
Our view, located at app/views/posts/rss/index.ctp, begins by setting the $documentData
and $channelData variables for the layout, these contain all the metadata for our RSS feed. This
is done by using the View::set() method which is analogous to the Controller::set() method. Here
though we are passing the channel's metadata back to the layout.
Plain Text View

$this->set('documentData', array(
'xmlns:dc' => 'http://purl.org/dc/elements/1.1/'));

$this->set('channelData', array(
'title' => __("Most Recent Posts", true),
'link' => $html->url('/', true),
'description' => __("Most recent posts.", true),
'language' => 'en-us'));
1. $this->set('documentData', array(
2. 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/'));
3. $this->set('channelData', array(
4. 'title' => __("Most Recent Posts", true),
5. 'link' => $html->url('/', true),
6. 'description' => __("Most recent posts.", true),
7. 'language' => 'en-us'));
The second part of the view generates the elements for the actual records of the feed. This is
accomplished by looping through the data that has been passed to the view ($items) and using
the RssHelper::item() method. The other method you can use, RssHelper::items() which takes a
callback and an array of items for the feed. (The method I have seen used for the callback has
always been called transformRss(). There is one downfall to this method, which is that you
cannot use any of the other helper classes to prepare your data inside the callback method
because the scope inside the method does not include anything that is not passed inside, thus not
giving access to the TimeHelper or any other helper that you may need. The RssHelper::item()
transforms the associative array into an element for each key value pair.
Plain Text View

foreach ($posts as $post) {


$postTime = strtotime($post['Post']['created']);

$postLink = array(
'controller' => 'entries',
'action' => 'view',
'year' => date('Y', $postTime),
'month' => date('m', $postTime),
'day' => date('d', $postTime),
$post['Post']['slug']);
// You should import Sanitize
App::import('Sanitize');
// This is the part where we clean the body text for output as the
description
// of the rss item, this needs to have only text to make sure the
feed validates
$bodyText = preg_replace('=\(.*?\)=is', '', $post['Post']['body']);
$bodyText = $text->stripLinks($bodyText);
$bodyText = Sanitize::stripAll($bodyText);
$bodyText = $text->truncate($bodyText, 400, '...', true, true);

echo $rss->item(array(), array(


'title' => $post['Post']['title'],
'link' => $postLink,
'guid' => array('url' => $postLink, 'isPermaLink' => 'true'),
'description' => $bodyText,
'dc:creator' => $post['Post']['author'],
'pubDate' => $post['Post']['created']));
}
1. foreach ($posts as $post) {
2. $postTime = strtotime($post['Post']['created']);
3.
4. $postLink = array(
5. 'controller' => 'entries',
6. 'action' => 'view',
7. 'year' => date('Y', $postTime),
8. 'month' => date('m', $postTime),
9. 'day' => date('d', $postTime),
10. $post['Post']['slug']);
11. // You should import Sanitize
12. App::import('Sanitize');
13. // This is the part where we clean the body text for output as the
description
14. // of the rss item, this needs to have only text to make sure the feed
validates
15. $bodyText = preg_replace('=\(.*?\)=is', '', $post['Post']['body']);
16. $bodyText = $text->stripLinks($bodyText);
17. $bodyText = Sanitize::stripAll($bodyText);
18. $bodyText = $text->truncate($bodyText, 400, '...', true, true);
19.
20. echo $rss->item(array(), array(
21. 'title' => $post['Post']['title'],
22. 'link' => $postLink,
23. 'guid' => array('url' => $postLink, 'isPermaLink' => 'true'),
24. 'description' => $bodyText,
25. 'dc:creator' => $post['Post']['author'],
26. 'pubDate' => $post['Post']['created']));
27. }
You can see above that we can use the loop to prepare the data to be transformed into XML
elements. It is important to filter out any non-plain text characters out of the description,
especially if you are using a rich text editor for the body of your blog. In the code above we use
the TextHelper::stripLinks() method and a few methods from the Sanitize class, but we
recommend writing a comprehensive text cleaning helper to really scrub the text clean. Once we
have set up the data for the feed, we can then use the RssHelper::item() method to create the
XML in RSS format. Once you have all this setup, you can test your RSS feed by going to your
site /posts/index.rss and you will see your new feed. It is always important that you validate your
RSS feed before making it live. This can be done by visiting sites that validate the XML such as
Feed Validator or the w3c site at http://validator.w3.org/feed/.
You may need to set the value of 'debug' in your core configuration to 1 or to 0 to
get a valid feed, because of the various debug information added automagically
under higher debug settings that break XML syntax or feed validation rules.

See comments for this section

« RSS | Session »
7.9 Session
• Edit
• Comments (0)
• History
As a natural counterpart to the Session Component, the Session Helper replicates most of the
components functionality and makes it available in your view. The Session Helper is
automatically added to your view — it is not necessary to add it to the $helpers array in the
controller.
The major difference between the Session Helper and the Session Component is that the helper
does not have the ability to write to the session.
As with the Session Component, data is written to and read by using dot separated array
structures.
Plain Text View

array('User' =>
array('username' => 'super@example.com')
);
1. array('User' =>
2. array('username' => 'super@example.com')
3. );
Given the previous array structure, the node would be accessed by User.username, with the dot
indicating the nested array. This notation is used for all Session helper methods wherever a $key
is used.
If you have Session.start set to false in your config/core.php, you need to call $session-
>activate(); in your view or layout before you can use any other method of Session helper.
Just like you need to call $this->Session->activate(); in your controller to activate Session
component.
« Creating an RSS feed with the RssHelper | Methods »

7.9.1 Methods
• Edit
• Comments (5)
• History
read($ke Read from the Session. Returns a string or array depending on the
y) contents of the session.
id() Returns the current session ID.

check($k Check to see if a key is in the Session. Returns a boolean on the key's
ey) existence.

flash($k This will echo the contents of the $_SESSION.Message. It is used in


ey) conjunction with the Session Component's setFlash() method.

error() Returns the last error in the session if one exists.

« Session | flash »

7.9.2 flash
• Edit
• Comments (0)
• History
The flash method uses the default key set by setFlash(). You can also retrieve specific keys in
the session. For example, the Auth component sets all of its Session messages under the 'auth'
key
Plain Text View

// Controller code
$this->Session->setFlash('My Message');

// In view
$session->flash();
// outputs "<div id='flashMessage' class='message'>My Message</div>"

// output the AuthComponent Session message, if set.


$session->flash('auth');
1. // Controller code
2. $this->Session->setFlash('My Message');
3. // In view
4. $session->flash();
5. // outputs "<div id='flashMessage' class='message'>My Message</div>"
6. // output the AuthComponent Session message, if set.
7. $session->flash('auth');
7.9.2.1 Using Flash for Success and Failure
• Edit
• View just this section
• Comments (0)
• History
In some web sites, particularly administration backoffice web applications it is often expected
that the result of an operation requested by the user has associated feedback as to whether the
operation succeeded or not. This is a classic usage for the flash mechanism since we only want to
show the user the result once and not keep the message.
One way to achieve this is to use Session->flash() with the layout parameter. With the layout
parameter we can be in control of the resultant html for the message.
In the controller you might typically have code:
Plain Text View

if ($user_was_deleted) {
$this->Session->setFlash('The user was deleted successfully.',
'flash_success');
} else {
$this->Session->setFlash('The user could not be deleted.',
'flash_failure');
}
1. if ($user_was_deleted) {
2. $this->Session->setFlash('The user was deleted successfully.',
'flash_success');
3. } else {
4. $this->Session->setFlash('The user could not be deleted.',
'flash_failure');
5. }
The flash_success and flash_failure parameter represents a layout file to place in the root
app/views/layouts folder, e.g. app/views/layouts/flash_success.ctp,
app/views/layouts/flash_failure.ctp
Inside the flash_success layout file would be something like this:
Plain Text View

echo "<div class=\"flash flash_success\">{$content_for_layout}</div>";


1. echo "<div class=\"flash flash_success\">{$content_for_layout}</div>";
The final step is in your main view file where the result is to be displayed to add simply
Plain Text View

<?php $session->flash(); ?>


1. <?php $session->flash(); ?>
And of course you can then add to your CSS a selector for div.flash, div.flash_success and
div.flash_failure
See comments for this section

« Methods | Text »
7.10 Text
• Edit
• Comments (1)
• History
The TextHelper contains methods to make text more usable and friendly in your views. It aids in
enabling links, formatting urls, creating excerpts of text around chosen words or phrases,
highlighting key words in blocks of text, and to gracefully truncating long stretches of text.
autoLinkEmails (string $text, array $htmlOptions=array())
Adds links to the well-formed email addresses in $text, according to any options defined in
$htmlOptions (see HtmlHelper::link()).
Plain Text View

$my_text = 'For more information regarding our world-famous pastries and


desserts, contact info@example.com';
$linked_text = $text->autoLinkEmails($my_text);

//$linked_text:
For more information regarding our world-famous pastries and desserts,
contact <a href="mailto:info@example.com"><u>info@example.com</u></a>
1. $my_text = 'For more information regarding our world-famous pastries
and desserts, contact info@example.com';
2. $linked_text = $text->autoLinkEmails($my_text);
3. //$linked_text:
4. For more information regarding our world-famous pastries and desserts,
5. contact <a href="mailto:info@example.com"><u>info@example.com</u></a>
autoLinkUrls ( string $text, array $htmlOptions=array() )
Same as in autoLinkEmails(), only this method searches for strings that start with https, http, ftp,
or nntp and links them appropriately.
autoLink (string $text, array $htmlOptions=array())
Performs the functionality in both autoLinkUrls() and autoLinkEmails() on the supplied $text.
All URLs and emails are linked appropriately given the supplied $htmlOptions.
excerpt (string $haystack, string $needle, int $radius=100, string $ending="...")
Extracts an excerpt from $haystack surrounding the $needle with a number of characters on each
side determined by $radius, and suffixed with $ending. This method is especially handy for
search results. The query string or keywords can be shown within the resulting document.
Plain Text View

<?php echo $text->excerpt($last_paragraph, 'method', 50); ?>


//Output
mined by $radius, and suffixed with $ending. This method is especially handy
for
search results. The query...
1. <?php echo $text->excerpt($last_paragraph, 'method', 50); ?>
2. //Output
3. mined by $radius, and suffixed with $ending. This method is especially
handy for
4. search results. The query...
highlight (string $haystack, string $needle, $highlighter= '< span
class="highlight">\1</span >')
Highlights $needle in $haystack using the $highlighter string specified.
Plain Text View

<?php echo $text->highlight($last_sentence, 'using'); ?>


//Output
Highlights $needle in $haystack <span class="highlight">using</span>
the $highlighter string specified.
1. <?php echo $text->highlight($last_sentence, 'using'); ?>
2. //Output
3. Highlights $needle in $haystack <span class="highlight">using</span>
4. the $highlighter string specified.
stripLinks ($text)
Strips the supplied $text of any HTML links.
toList (array $list, $and= 'and')
Creates a comma-separated list where the last two items are joined with ‘and’.
Plain Text View

<?php echo $text->toList($colors); ?>

//Output<br />red, orange, yellow, green, blue, indigo and violet


1. <?php echo $text->toList($colors); ?>
2. //Output<br />red, orange, yellow, green, blue, indigo and violet
truncate (string $text, int $length=100, array $options=array(string $ending='...', boolean
$exact=true, boolean $html=false))
trim(); // an alias for truncate
Cuts a string to the $length and suffix with $ending if the text is longer than $length. If $exact is
passed as false, the truncation will occur after the next word ending. If $html is passed as true,
html tags will be respected and will not be cut off.
Plain Text View

<?php
echo $text->truncate(
'The killer crept forward and tripped on the rug.',
22,
'...',
false
);
?>
1. <?php
2. echo $text->truncate(
3. 'The killer crept forward and tripped on the rug.',
4. 22,
5. '...',
6. false
7. );
8. ?>
Plain Text View
//Output:
The killer crept...
1. //Output:
2. The killer crept...
« flash | Time »

7.11 Time
• Edit
• Comments (0)
• History
The Time Helper does what it says on the tin: saves you time. It allows for the quick processing
of time related information. The Time Helper has two main tasks that it can perform:
1. It can format time strings.
2. It can test time (but cannot bend time, sorry).
« Text | Formatting »

7.11.1 Formatting
• Edit
• Comments (0)
• History
fromString( $date_string )
fromString takes a string and uses strtotime to convert it into a date object. If the string passed
in is a number then it'll convert it into an integer, being the number of seconds since the Unix
Epoch (January 1 1970 00:00:00 GMT). Passing in a string of "20081231" will create undesired
results as it will covert it to the number of seconds from the Epoch, in this case "Fri, Aug 21st
1970, 06:07"
toQuarter( $date_string, $range = false )
toQuarter will return 1, 2, 3 or 4 depending on what quarter of the year the date falls in. If range
is set to true, a two element array will be returned with start and end dates in the format "2008-
03-31".
toUnix( $date_string )
toUnix is a wrapper for fromString.
toAtom( $date_string )
toAtom return a date string in the Atom format "2008-01-12T00:00:00Z"
toRSS( $date_string )
toRSS returns a date string in the RSS format "Sat, 12 Jan 2008 00:00:00 -0500"
nice( $date_string = null )
nice takes a date string and outputs it in the format "Tue, Jan 1st 2008, 19:25".
niceShort( $date_string = null )
niceShort takes a date string and outputs it in the format "Jan 1st 2008, 19:25". If the date object
is today, the format will be "Today, 19:25". If the date object is yesterday, the format will be
"Yesterday, 19:25".
daysAsSql( $begin, $end, $fieldName, $userOffset = NULL )
daysAsSql returns a string in the format "($field_name >= '2008-01-21 00:00:00') AND
($field_name <= '2008-01-25 23:59:59')". This is handy if you need to search for records
between two dates inclusively.
dayAsSql( $date_string, $field_name )
dayAsSql creates a string in the same format as daysAsSql but only needs a single date object.
timeAgoInWords( $datetime_string, $options = array(), $backwards = null )
timeAgoInWords will take a datetime string (anything that is parsable by PHP's strtotime()
function or MySQL's datetime format) and convert it into a friendly word format like, "3 weeks,
3 days ago". Passing in true for $backwards will specifically declare the time is set in the future,
which uses the format "on 31/12/08".
Optio
Description
n

forma
a date format; default "on 31/12/08"
t

determines the cutoff point in which it no longer uses words and uses the date
end
format instead; default "+1 month"

relativeTime( $date_string, $format = 'j/n/y' )


relativeTime is essentially an alias for timeAgoInWords.
gmt( $date_string = null )
gmt will return the date as an integer set to Greenwich Mean Time (GMT).
format( $format = 'd-m-Y', $date_string)
format is a wrapper for the PHP date function.
Function Format

nice Tue, Jan 1st 2008, 19:25

Jan 1st 2008, 19:25


niceShort Today, 19:25
Yesterday, 19:25

($field_name >= '2008-01-21 00:00:00') AND ($field_name <=


daysAsSql
'2008-01-25 23:59:59')

($field_name >= '2008-01-21 00:00:00') AND ($field_name <=


dayAsSql
'2008-01-21 23:59:59')

on 21/01/08
timeAgoInWo
3 months, 3 weeks, 2 days ago
rds
7 minutes ago
relativeTime
2 seconds ago

gmt 1200787200

« Time | Testing Time »

7.11.2 Testing Time


• Edit
• Comments (0)
• History
• isToday
• isThisWeek
• isThisMonth
• isThisYear
• wasYesterday
• isTomorrow
• wasWithinLast
All of the above functions return true or false when passed a date string. wasWithinLast takes
an additional $time_interval option:
$time->wasWithinLast( $time_interval, $date_string )
wasWithinLast takes a time interval which is a string in the format "3 months" and accepts a
time interval of seconds, minutes, hours, days, weeks, months and years (plural and not). If a
time interval is not recognized (for example, if it is mistyped) then it will default to days.
« Formatting | XML »

7.12.1 serialize
• Edit
• Comments (0)
• History
serialize($data, $options = array())
• mixed $data - The content to be converted to XML
• mixed $options - The data formatting options. For a list of valid options, see
Xml::__construct()
○ string $options['root'] - The name of the root element, defaults to
'#document'
○ string $options['version'] - The XML version, defaults to '1.0'
○ string $options['encoding'] - Document encoding, defaults to 'UTF-8'
○ array $options['namespaces'] - An array of namespaces (as strings)
used in this document
○ string $options['format'] - Specifies the format this document converts
to when parsed or rendered out as text, either 'attributes' or 'tags',
defaults to 'attributes'
○ array $options['tags'] - An array specifying any tag-specific formatting
options, indexed by tag name. See XmlNode::normalize()
The serialize method takes an array and creates an XML string of the data. This is commonly
used for serializing model data.
Plain Text View

<?php
echo $xml->serialize($data);
format will be similar to:
<model_name id="1" field_name="content" />
?>
1. <?php
2. echo $xml->serialize($data);
3. format will be similar to:
4. <model_name id="1" field_name="content" />
5. ?>
The serialize method acts as a shortcut to instantiating the XML built-in class and using the
toString method of that. If you need more control over serialization, you may wish to invoke the
XML class directly.
You can modify how a data is serialized by using the format attribute. By default the data will be
serialized as attributes. If you set the format as "tags" the data will be serialized as tags.
Plain Text View

pr($data);
1. pr($data);
Array
(
[Baker] => Array
(
[0] => Array
(
[name] => The Baker
[weight] => heavy
)
[1] => Array
(
[name] => The Cook
[weight] => light-weight
)
)
)
Plain Text View

pr($xml->serialize($data));
1. pr($xml->serialize($data));
<baker>
<baker name="The Baker" weight="heavy" />
<baker name="The Cook" weight="light-weight" />
</baker>
Plain Text View

pr($xml->serialize($data, array('format' => 'tags')));


1. pr($xml->serialize($data, array('format' => 'tags')));
<baker>
<baker>
<name><![CDATA[The Baker]]></name>
<weight><![CDATA[heavy]]></weight>
</baker>
<baker>
<name><![CDATA[The Cook]]></name>
<weight><![CDATA[light-weight]]></weight>
</baker>
</baker>
« XML | elem »

7.12.2 elem
• Edit
• Comments (2)
• History
The elem method allows you to build an XML node string with attributes and internal content, as
well.
string elem (string $name, $attrib = array(), mixed $content = null, $endTag = true)
Plain Text View

echo $xml->elem('count', array('namespace' => 'myNameSpace'), 'content');


// generates: <myNameSpace:count>content</count>
1. echo $xml->elem('count', array('namespace' => 'myNameSpace'),
'content');
2. // generates: <myNameSpace:count>content</count>
If you want to wrap your text node with CDATA, the third argument should be an array
containing two keys: 'cdata' and 'value'
Plain Text View

echo $xml->elem('count', null, array('cdata'=>true,'value'=>'content'));


// generates: <count><![CDATA[content]]></count>
1. echo $xml->elem('count', null, array('cdata'=>true,'value'=>'content'));
2. // generates: <count><![CDATA[content]]></count>
« serialize | header »

7.12.3 header
• Edit
• Comments (0)
• History
The header() method is used to output the XML declaration.
Plain Text View
<?php
echo $xml->header();
// generates: <?xml version="1.0" encoding="UTF-8" ?>
?>
1. <?php
2. echo $xml->header();
3. // generates: <?xml version="1.0" encoding="UTF-8" ?>
4. ?>
You can pass in a different version number and encoding type as parameters of the header
method.
Plain Text View

<?php
echo $xml->header(array('version'=>'1.1'));
// generates: <?xml version="1.1" encoding="UTF-8" ?>
?>
1. <?php
2. echo $xml->header(array('version'=>'1.1'));
3. // generates: <?xml version="1.1" encoding="UTF-8" ?>
4. ?>
« elem | Core Utility Libraries »

8.1 App
• Edit
• Comments (0)
• History
App is a very small utility library. It only contains the import method. But, with the import
method, you can accomplish a lot.
Plain Text View

// examples
App::Import('Core','File');
App::Import('Model','Post');
App::import('Vendor', 'geshi');
App::import('Vendor', 'flickr/flickr');
App::import('Vendor', 'SomeName', array('file' => 'some.name.php'));
App::import('Vendor', 'WellNamed', array('file' =>
'services'.DS.'well.named.php'));
1. // examples
2. App::Import('Core','File');
3. App::Import('Model','Post');
4. App::import('Vendor', 'geshi');
5. App::import('Vendor', 'flickr/flickr');
6. App::import('Vendor', 'SomeName', array('file' => 'some.name.php'));
7. App::import('Vendor', 'WellNamed', array('file' =>
'services'.DS.'well.named.php'));
You can read more about it in the book or the API documentation
« Core Utility Libraries | Inflector »

8.2 Inflector
• Edit
• Comments (1)
• History
The Inflector class takes a string and can manipulate it to handle word variations such as
pluralizations or camelizing and is normally accessed statically. Example:
Inflector::pluralize('example') returns "examples".
« App | Class methods »

8.2.1 Class methods


• Edit
• Comments (0)
• History
Input Output

pluralize Apple, Orange, Person, Man Apples, Oranges, People, Men

singulari
Apples, Oranges, People, Men Apple, Orange, Person, Man
ze

camelize Apple_pie, some_thing, ApplePie, SomeThing, PeoplePerson


people_person

It should be noted that underscore will only convert camelCase formatted


undersc words. Words that contains spaces will be lower-cased, but will not contain
ore an underscore.

applePie, someThing apple_pie, some_thing

humaniz apple_pie, some_thing, Apple Pie, Some Thing, People


e people_person Person

tableize Apple, UserProfileSetting, Person apples, user_profile_settings, people

classify apples, user_profile_settings, people Apple, UserProfileSetting, Person

variable apples, user_result, people_people apples, userResult, peoplePeople

Slug converts special characters into latin versions and converting


unmatched characters and spaces to underscores. The slug method
slug expects UTF-8 encoding.

apple purée apple_puree

« Inflector | String »

8.3 String
• Edit
• Comments (0)
• History
The String class includes convenience methods for creating and manipulating strings and is
normally accessed statically. Example: String::uuid().
« Class methods | uuid »

8.3.1 uuid
• Edit
• Comments (0)
• History
The uuid method is used to generate unique identifiers as per RFC 4122. The uuid is a 128bit
string in the format of 485fc381-e790-47a3-9794-1337c0a8fe68.
Plain Text View

String::uuid(); // 485fc381-e790-47a3-9794-1337c0a8fe68
1. String::uuid(); // 485fc381-e790-47a3-9794-1337c0a8fe68
« String | tokenize »

8.3.2 tokenize
• Edit
• Comments (1)
• History
string tokenize ($data, $separator = ',', $leftBound = '(', $rightBound =
')')
Tokenizes a string using $separator, ignoring any instance of $separator that appears
between $leftBound and $rightBound.
« uuid | insert »

8.3.3 insert
• Edit
• Comments (0)
• History
string insert ($string, $data, $options = array())
The insert method is used to create string templates and to allow for key/value replacements.
Plain Text View

String::insert('My name is :name and I am :age years old.', array('name' =>


'Bob', 'age' => '65'));
// generates: "My name is Bob and I am 65 years old."
1. String::insert('My name is :name and I am :age years old.',
array('name' => 'Bob', 'age' => '65'));
2. // generates: "My name is Bob and I am 65 years old."
« tokenize | cleanInsert »
8.3.4 cleanInsert
• Edit
• Comments (0)
• History
string cleanInsert ($string, $options = array())
Cleans up a Set::insert formatted string with given $options depending on the 'clean' key in
$options. The default method used is text but html is also available. The goal of this function is
to replace all whitespace and unneeded markup around placeholders that did not get replaced by
Set::insert.
You can use the following options in the options array:
Plain Text View

$options = array(
'clean' => array(
'method' => 'text', // or html
),

'before' => '',


'after' => ''
);
1. $options = array(
2. 'clean' => array(
3. 'method' => 'text', // or html
4. ),
5. 'before' => '',
6. 'after' => ''
7. );
« insert | Xml »

8.4.1 Xml parsing


• Edit
• Comments (0)
• History
Parsing Xml with the Xml class requires you to have a string containing the xml you wish to
parse.
Plain Text View

$input = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>


<container>
<element id="first-el">
<name>My element</name>
<size>20</size>
</element>
<element>
<name>Your element</name>
<size>30</size>
</element>
</container>';
$xml = new Xml($input);
1. $input = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>
2. <container>
3. <element id="first-el">
4. <name>My element</name>
5. <size>20</size>
6. </element>
7. <element>
8. <name>Your element</name>
9. <size>30</size>
10. </element>
11. </container>';
12. $xml = new Xml($input);
This would create an Xml document object that can then be manipulated and traversed, and
reconverted back into a string.
With the sample above you could do the following.
Plain Text View

echo $xml->children[0]->children[0]->name;
// outputs 'element'

echo $xml->children[0]->children[0]->children[0]->children[0]->value;
// outputs 'My Element'

echo $xml->children[0]->child('element')->attributes['id'];
//outputs 'first-el'
1. echo $xml->children[0]->children[0]->name;
2. // outputs 'element'
3. echo $xml->children[0]->children[0]->children[0]->children[0]->value;
4. // outputs 'My Element'
5. echo $xml->children[0]->child('element')->attributes['id'];
6. //outputs 'first-el'
In addition to the above it often makes it easier to obtain data from XML if you convert the Xml
document object to a array.
Plain Text View

$xml = new Xml($input);


// This converts the Xml document object to a formatted array
$xmlAsArray = Set::reverse($xml);
// Or you can convert simply by calling toArray();
$xmlAsArray = $xml->toArray();
1. $xml = new Xml($input);
2. // This converts the Xml document object to a formatted array
3. $xmlAsArray = Set::reverse($xml);
4. // Or you can convert simply by calling toArray();
5. $xmlAsArray = $xml->toArray();
« Xml | Set »

8.5.1 Set-compatible Path syntax


• Edit
• Comments (0)
• History
The Path syntax is used by (for example) sort, and is used to define a path.
Usage example (using Set::sort()):
Plain Text View

$a = array(
0 => array('Person' => array('name' => 'Jeff')),
1 => array('Shirt' => array('color' => 'black'))
);
$result = Set::sort($a, '{n}.Person.name', 'asc');
/* $result now looks like:
Array
(
[0] => Array
(
[Shirt] => Array
(
[color] => black
)
)
[1] => Array
(
[Person] => Array
(
[name] => Jeff
)
)
)
*/
1. $a = array(
2. 0 => array('Person' => array('name' => 'Jeff')),
3. 1 => array('Shirt' => array('color' => 'black'))
4. );
5. $result = Set::sort($a, '{n}.Person.name', 'asc');
6. /* $result now looks like:
7. Array
8. (
9. [0] => Array
10. (
11. [Shirt] => Array
12. (
13. [color] => black
14. )
15. )
16. [1] => Array
17. (
18. [Person] => Array
19. (
20. [name] => Jeff
21. )
22. )
23. )
24. */
As you can see in the example above, some things are wrapped in {}'s, others not. In the table
below, you can see which options are available.
Express
Definition
ion

{n} Represents a numeric key

{s} Represents a string

Foo Any string (without enclosing brackets) is treated like a string literal.

{[a-z] Any string enclosed in brackets (besides {n} and {s}) is interpreted as
+} a regular expression.

This section needs to be expanded.

« Set | insert »

8.5.2 insert
• Edit
• Comments (0)
• History
array Set::insert ($list, $path, $data = null)
Inserts $data into an array as defined by $path.
Plain Text View

$a = array(
'pages' => array('name' => 'page')
);
$result = Set::insert($a, 'files', array('name' => 'files'));
/* $result now looks like:
Array
(
[pages] => Array
(
[name] => page
)
[files] => Array
(
[name] => files
)
)
*/

$a = array(
'pages' => array('name' => 'page')
);
$result = Set::insert($a, 'pages.name', array());
/* $result now looks like:
Array
(
[pages] => Array
(
[name] => Array
(
)
)
)
*/
$a = array(
'pages' => array(
0 => array('name' => 'main'),
1 => array('name' => 'about')
)
);
$result = Set::insert($a, 'pages.1.vars', array('title' => 'page title'));
/* $result now looks like:
Array
(
[pages] => Array
(
[0] => Array
(
[name] => main
)
[1] => Array
(
[name] => about
[vars] => Array
(
[title] => page title
)
)
)
)
*/
1. $a = array(
2. 'pages' => array('name' => 'page')
3. );
4. $result = Set::insert($a, 'files', array('name' => 'files'));
5. /* $result now looks like:
6. Array
7. (
8. [pages] => Array
9. (
10. [name] => page
11. )
12. [files] => Array
13. (
14. [name] => files
15. )
16. )
17. */
18. $a = array(
19. 'pages' => array('name' => 'page')
20. );
21. $result = Set::insert($a, 'pages.name', array());
22. /* $result now looks like:
23. Array
24. (
25. [pages] => Array
26. (
27. [name] => Array
28. (
29. )
30. )
31. )
32. */
33. $a = array(
34. 'pages' => array(
35. 0 => array('name' => 'main'),
36. 1 => array('name' => 'about')
37. )
38. );
39. $result = Set::insert($a, 'pages.1.vars', array('title' => 'page
title'));
40. /* $result now looks like:
41. Array
42. (
43. [pages] => Array
44. (
45. [0] => Array
46. (
47. [name] => main
48. )
49. [1] => Array
50. (
51. [name] => about
52. [vars] => Array
53. (
54. [title] => page title
55. )
56. )
57. )
58. )
59. */
« Set-compatible Path syntax | sort »

You might also like