You are on page 1of 1107

CakePHP Cookbook Documentation

Release 2.x

Cake Software Foundation

March 21, 2016

Contents

1

Getting Started
1
Blog Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Blog Tutorial - Adding a layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2

Installation
Requirements . . . . . . . . . . . . . . .
License . . . . . . . . . . . . . . . . . .
Downloading CakePHP . . . . . . . . . .
Permissions . . . . . . . . . . . . . . . .
Setup . . . . . . . . . . . . . . . . . . .
Development . . . . . . . . . . . . . . .
Production . . . . . . . . . . . . . . . . .
Advanced Installation and URL Rewriting
Fire It Up . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

31
31
31
32
32
32
33
34
34
42

3

CakePHP Overview
45
What is CakePHP? Why use it? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Understanding Model-View-Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Where to Get Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4

Controllers
The App Controller . . . . .
Request parameters . . . . .
Controller actions . . . . . .
Request Life-cycle callbacks
Controller Methods . . . . .
Controller Attributes . . . .
More on controllers . . . . .

5

Views

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

51
51
52
52
53
54
61
63
85
i

View Templates . . . . . . . .
Using view blocks . . . . . . .
Layouts . . . . . . . . . . . .
Elements . . . . . . . . . . . .
Creating your own view classes
View API . . . . . . . . . . .
More about Views . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

85
87
89
91
94
95
97

6

Models
207
Understanding Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
More on models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

7

Core Libraries
General Purpose
Behaviors . . .
Components . .
Helpers . . . .
Utilities . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

343
343
508
538
591
690

8

Plugins
807
How To Install Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
How To Use Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809
How To Create Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811

9

Shells, Tasks & Console Tools
The CakePHP console . . . . . . . . . .
Creating a shell . . . . . . . . . . . . .
Shell tasks . . . . . . . . . . . . . . . .
Invoking other shells from your shell . .
Console output levels . . . . . . . . . .
Styling output . . . . . . . . . . . . . .
Configuring options and generating help
Routing in shells / CLI . . . . . . . . .
Shell API . . . . . . . . . . . . . . . .
More topics . . . . . . . . . . . . . . .

10 Development
Configuration . .
Routing . . . . .
Sessions . . . . .
Exceptions . . . .
Error Handling .
Debugging . . . .
Testing . . . . . .
REST . . . . . .
Dispatcher Filters

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

817
817
819
821
822
822
823
824
831
832
835

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

855
855
869
887
893
900
902
906
930
934

11 Deployment
939
Check your security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
ii

Set document root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
Update core.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
Improve your application’s performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940
12 Simple Authentication and Authorization Application
941
Creating all users’ related code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941
Authentication (login and logout) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
Authorization (who’s allowed to access what) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
13 Simple Acl controlled Application
Preparing our Application . . . . . . . . .
Preparing to Add Auth . . . . . . . . . .
Initialize the Db Acl tables . . . . . . . .
Acts As a Requester . . . . . . . . . . . .
Creating ACOs (Access Control Objects)

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

951
951
953
955
955
957

14 Simple Acl controlled Application - part 2
An Automated tool for creating ACOs . . .
Setting up permissions . . . . . . . . . . .
Logging in . . . . . . . . . . . . . . . . . .
Logout . . . . . . . . . . . . . . . . . . . .
All done . . . . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

959
959
959
961
962
962

15 Contributing
Documentation . . . . . . . . .
Tickets . . . . . . . . . . . . . .
Code . . . . . . . . . . . . . . .
Coding Standards . . . . . . . .
Backwards Compatibility Guide
CakePHP Development Process

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

963
963
972
972
975
986
989

16 Appendices
2.8 Migration Guide . . .
2.7 Migration Guide . . .
2.6 Migration Guide . . .
2.5 Migration Guide . . .
2.4 Migration Guide . . .
2.3 Migration Guide . . .
2.2 Migration Guide . . .
2.1 Migration Guide . . .
2.0 Migration Guide . . .
Migration from 1.2 to 1.3
General Information . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

991
991
993
995
998
1004
1010
1016
1022
1033
1066
1087

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

17 Indices and tables

1089

Index

1091

iii

iv

CHAPTER 1

Getting Started

The CakePHP framework provides a robust base for your application. It can handle every aspect, from the
user’s initial request all the way to the final rendering of a web page. And since the framework follows the
principles of MVC, it allows you to easily customize and extend most aspects of your application.
The framework also provides a basic organizational structure, from filenames to database table names, keeping your entire application consistent and logical. This concept is simple but powerful. Follow the conventions and you’ll always know exactly where things are and how they’re organized.
The best way to experience and learn CakePHP is to sit down and build something. To start off we’ll build
a simple blog application.

Blog Tutorial
Welcome to CakePHP. You’re probably checking out this tutorial because you want to learn more about how
CakePHP works. It’s 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
CakePHP, 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 CakePHP up and running without any configuration at all. Make sure you have
PHP 5.2.8 or greater.
2. A database server. We’re going to be using MySQL server in this tutorial. You’ll need to know enough
about SQL in order to create a database: CakePHP will be taking the reins from there. Since we’re
using MySQL, also make sure that you have pdo_mysql enabled in PHP.
3. Basic PHP knowledge. The more object-oriented programming you’ve done, the better: but fear not
if you’re a procedural fan.
1

CakePHP Cookbook Documentation, Release 2.x

4. Finally, you’ll need a basic knowledge of the MVC programming pattern. A quick overview can be
found in Understanding Model-View-Controller. Don’t worry, it’s only half a page or so.
Let’s get started!

Getting CakePHP
First, let’s get a copy of fresh CakePHP code.
To get a fresh download, visit the CakePHP project on GitHub: https://github.com/cakephp/cakephp/tags
and download the latest release of 2.0
You can also clone the repository using git1 . git clone git://github.com/cakephp/cakephp.git
Regardless of how you downloaded it, place the code inside of your DocumentRoot. Once finished, your
directory setup should look something like the following:
/path_to_document_root
/app
/lib
/plugins
/vendors
.htaccess
index.php
README

Now might be a good time to learn a bit about how CakePHP’s directory structure works: check out the
CakePHP Folder Structure section.
Tmp directory permissions
Next we’ll need to make the app/tmp directory writable by the webserver. The best way to do this is to
find out what user your webserver runs as. You can run <?php echo exec(’whoami’); ?> inside
any PHP file your webserver can execute. You should see a username printed. Change the ownership of the
app/tmp directory to that user. The final command you run (in *nix) might look something like this:
$ chown -R www-data app/tmp

If for some reason CakePHP can’t write to that directory, you’ll see warnings and uncaught exceptions that
cache data cannot be written.

Creating the Blog Database
Next, let’s set up the underlying database for our blog. If you haven’t already done so, create an empty
database for use in this tutorial, with a name of your choice. 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:
1

2

http://git-scm.com/

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

/* First, create our posts table: */
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
/* Then insert some posts for testing: */
INSERT INTO posts (title, body, created)
VALUES ('The title', 'This is the post body.', NOW());
INSERT INTO posts (title, body, created)
VALUES ('A title once again', 'And the post body follows.', NOW());
INSERT INTO posts (title, body, created)
VALUES ('Title strikes back', 'This is really exciting! Not.', NOW());

The choices on table and column names are not arbitrary. If you follow CakePHP’s database naming conventions, and CakePHP’s class naming conventions (both outlined in CakePHP Conventions), you’ll be able
to take advantage of a lot of free functionality and avoid configuration. CakePHP is flexible enough to
accommodate even the worst legacy database schema, but adhering to convention will save you time.
Check out CakePHP 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 CakePHP.

CakePHP Database Configuration
Onward and upward: let’s tell CakePHP where our database is and how to connect to it. For many, this is
the first and last time you configure anything.
A
copy
of
CakePHP’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:
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'port' => '',
'login' => 'cakeBlog',
'password' => 'c4k3-rUl3Z',
'database' => 'cake_blog_tutorial',
'schema' => '',
'prefix' => '',
'encoding' => 'utf8'
);

Once you’ve saved your new database.php file, you should be able to open your browser and see the
Blog Tutorial

3

CakePHP Cookbook Documentation, Release 2.x

CakePHP welcome page. It should also tell you that your database connection file was found, and that
CakePHP can successfully connect to the database.
Note: Remember that you’ll need to have PDO, and pdo_mysql enabled in your php.ini.

Optional Configuration
There are a few other items that can be configured. Most developers complete these laundry-list items, but
they’re not required for this tutorial. One is defining a custom string (or “salt”) for use in security hashes.
The second is defining a custom number (or “seed”) for use in encryption.
The security salt is used for generating hashes. Change the default Security.salt value in
/app/Config/core.php. The replacement value should be long, hard to guess and be as random
as you can make it:
/**
* A random string used in security hashing methods.
*/
Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!');

The cipher seed is used for encrypt/decrypt strings. Change the default Security.cipherSeed value
by editing /app/Config/core.php. The replacement value should be a large random integer:
/**
* A random numeric string (digits only) used to encrypt/decrypt strings.
*/
Configure::write('Security.cipherSeed', '7485712659625147843639846751');

A Note on mod_rewrite
Occasionally new users will run into mod_rewrite issues. For example if the CakePHP welcome page looks
a little funny (no images or CSS styles), it probably means mod_rewrite is not functioning on your system.
Please refer to one of the sections below about URL rewriting for your webserver to get you up and running:
URL Rewriting
Apache and mod_rewrite (and .htaccess)

While CakePHP is built to work with mod_rewrite out of the box–and usually does–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. First look at your httpd.conf. (Make sure you
are editing the system httpd.conf rather than a user- or site-specific httpd.conf.)
These files can vary between different distributions and Apache versions. You may also take a look at
http://wiki.apache.org/httpd/DistrosDefaultLayout for further information.

4

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

1. Make sure that an .htaccess override is allowed and that AllowOverride is set to All for the correct
DocumentRoot. You should see something similar to:
# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# features.
#
<Directory />
Options FollowSymLinks
AllowOverride All
#
Order deny,allow
#
Deny from all
</Directory>

For users having apache 2.4 and above, you need to modify the configuration file for your
httpd.conf or virtual host configuration to look like the following:
<Directory /var/www/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>

2. Make sure you are loading mod_rewrite correctly. You should see something like:
LoadModule rewrite_module libexec/apache2/mod_rewrite.so

In many systems these will be commented out by default, so you may just need to remove the leading
# symbols.
After you make changes, restart Apache to make sure the settings are active.
Verify that your .htaccess files are actually in the right directories. Some operating systems treat files
that start with ‘.’ as hidden and therefore won’t copy them.
3. Make sure your copy of CakePHP comes from the downloads section of the site or our Git repository,
and has been unpacked correctly, by checking for .htaccess files.
CakePHP root directory (must be copied to your document; redirects everything to your CakePHP
app):
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule
^$ app/webroot/
[L]
RewriteRule
(.*) app/webroot/$1 [L]
</IfModule>

CakePHP app directory (will be copied to the top directory of your application by bake):
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule
^$
webroot/

Blog Tutorial

[L]

5

CakePHP Cookbook Documentation, Release 2.x

RewriteRule
</IfModule>

(.*) webroot/$1

[L]

CakePHP webroot directory (will be copied to your application’s web root by bake):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

If your CakePHP site still has problems with mod_rewrite, you might want to try modifying settings
for Virtual Hosts. On Ubuntu, edit the file /etc/apache2/sites-available/default (location is distributiondependent). In this file, ensure that AllowOverride None is changed to AllowOverride
All, so you have:
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /var/www>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order Allow,Deny
Allow from all
</Directory>

On Mac OSX, another solution is to use the tool virtualhostx2 to make a Virtual Host to point to your
folder.
For many hosting services (GoDaddy, 1and1), your web server is actually being served from a
user directory that already uses mod_rewrite. If you are installing CakePHP into a user directory (http://example.com/~username/cakephp/), or any other URL structure that already utilizes
mod_rewrite, you’ll need to add RewriteBase statements to the .htaccess files CakePHP uses (/.htaccess, /app/.htaccess, /app/webroot/.htaccess).
This can be added to the same section with the RewriteEngine directive, so for example, your webroot
.htaccess file would look like:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /path/to/cake/app
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

The details of those changes will depend on your setup, and can include additional things that are not
related to CakePHP. Please refer to Apache’s online documentation for more information.
2

6

http://clickontyler.com/virtualhostx/

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

4. (Optional) To improve production setup, you should prevent invalid assets from being parsed by
CakePHP. Modify your webroot .htaccess to something like:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /path/to/cake/app
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/(app/webroot/)?(img|css|js)/(.*)$
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

The above will simply prevent incorrect assets from being sent to index.php and instead display your
webserver’s 404 page.
Additionally you can create a matching HTML 404 page, or use the default built-in CakePHP 404 by
adding an ErrorDocument directive:
ErrorDocument 404 /404-not-found

Pretty URLs on nginx

nginx does not make use of .htaccess files like Apache, so it is necessary to create those rewritten URLs in
the site-available configuration. Depending upon your setup, you will have to modify this, but at the very
least, you will need PHP running as a FastCGI instance.
server {
listen
80;
server_name www.example.com;
rewrite ^(.*) http://example.com$1 permanent;
}
server {
listen
80;
server_name example.com;
# root directive should be global
root
/var/www/example.com/public/app/webroot/;
index index.php;
access_log /var/www/example.com/log/access.log;
error_log /var/www/example.com/log/error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass
127.0.0.1:9000;
fastcgi_index
index.php;

Blog Tutorial

7

CakePHP Cookbook Documentation, Release 2.x

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

If for some exotic reason you cannot change your root directory and need to run your project from a subfolder
like example.com/subfolder/, you will have to inject “/webroot” in each request.
location ~ ^/(subfolder)/(.*)? {
index index.php;
set $new_uri /$1/webroot/$2;
try_files $new_uri $new_uri/ /$1/index.php?$args;
... php handling ...
}

Note: Recent configuration of PHP-FPM is set to listen to php-fpm socket instead of TCP port 9000 on
address 127.0.0.1. If you get 502 bad gateway error from above configuration, try replacing fastcgi_pass
from TCP port to socket path (eg: fastcgi_pass unix:/var/run/php5-fpm.sock;).

URL Rewrites on IIS7 (Windows hosts)

IIS7 does not natively support .htaccess files. While there are add-ons that can add this support, you can
also import htaccess rules into IIS to use CakePHP’s native rewrites. To do this, follow these steps:
1. Use Microsoft’s Web Platform Installer3 to install the URL Rewrite Module 2.04 or download it
directly (32-bit5 / 64-bit6 ).
2. Create a new file called web.config in your CakePHP root folder.
3. Using Notepad or any XML-safe editor, copy the following code into your new web.config file...
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite requests to test.php"
stopProcessing="true">
<match url="^test.php(.*)$" ignoreCase="false" />
<action type="Rewrite" url="app/webroot/test.php{R:1}" />
</rule>
<rule name="Exclude direct access to app/webroot/*"
stopProcessing="true">
<match url="^app/webroot/(.*)$" ignoreCase="false" />
<action type="None" />
</rule>
3

http://www.microsoft.com/web/downloads/platform.aspx
http://www.iis.net/downloads/microsoft/url-rewrite
5
http://www.microsoft.com/en-us/download/details.aspx?id=5747
6
http://www.microsoft.com/en-us/download/details.aspx?id=7435
4

8

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

<rule name="Rewrite routed access to assets(img, css, files, js, favicon)"
stopProcessing="true">
<match url="^(img|css|files|js|favicon.ico)(.*)$" />
<action type="Rewrite" url="app/webroot/{R:1}{R:2}"
appendQueryString="false" />
</rule>
<rule name="Rewrite requested file/folder to index.php"
stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<action type="Rewrite" url="index.php"
appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Once the web.config file is created with the correct IIS-friendly rewrite rules, CakePHP’s links, CSS, JavaScipt, and rerouting should work correctly.
URL-Rewriting on lighttpd

Lighttpd does not support .htaccess functions, so you can remove all .htaccess files. In the lighttpd configuration, make sure you’ve activated “mod_rewrite”. Add a line:
url.rewrite-if-not-file =(
"^([^\?]*)(\?(.+))?$" => "/index.php?url=$1&$3"
)

URL rewrite rules for Hiawatha

The required UrlToolkit rule (for URL rewriting) to use CakePHP with Hiawatha is:
UrlToolkit {
ToolkitID = cakephp
RequestURI exists Return
Match .* Rewrite /index.php
}

I don’t / can’t use URL rewriting

If you don’t want to or can’t use URL rewriting on your webserver, refer to the core configuration.
Now continue to /tutorials-and-examples/blog/part-two to start building your first
CakePHP application.

Blog Tutorial

9

CakePHP Cookbook Documentation, Release 2.x

Blog Tutorial - Adding a layer
Create a Post Model
The Model class is the bread and butter of CakePHP applications. By creating a CakePHP model that will
interact with our database, we’ll have the foundation in place needed to do our view, add, edit, and delete
operations later.
CakePHP’s model class files go in /app/Model, and the file we’ll be creating will be saved to
/app/Model/Post.php. The completed file should look like this:
class Post extends AppModel {
}

Naming conventions are very important in CakePHP. By naming our model Post, CakePHP can automatically infer that this model will be used in the PostsController, and will be tied to a database table called
posts.
Note: CakePHP will dynamically create a model object for you if it cannot find a corresponding file
in /app/Model. This also means that if you accidentally name your file wrong (for example, post.php or
posts.php instead of Post.php), CakePHP will not recognize any of your settings and will use the defaults
instead.
For more on models, such as table prefixes, callbacks, and validation, check out the Models chapter of the
Manual.

Create a Posts Controller
Next, we’ll create a controller for our posts. The controller is where all the business logic for post interaction
will happen. In a nutshell, it’s the place where you play with the models and get post-related work done.
We’ll place this new controller in a file called PostsController.php inside the /app/Controller
directory. Here’s what the basic controller should look like:
class PostsController extends AppController {
public $helpers = array('Html', 'Form');
}

Now, let’s add an action to our controller. Actions often represent a single function or interface in
an application. For example, when users request www.example.com/posts/index (which is the same as
www.example.com/posts/), they might expect to see a listing of posts. The code for that action would look
something like this:
class PostsController extends AppController {
public $helpers = array('Html', 'Form');
public function index() {
$this->set('posts', $this->Post->find('all'));
}
}

10

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

By defining function index() in our PostsController, users can access the logic there by requesting
www.example.com/posts/index. Similarly, if we were to define a function called foobar(), users would
be able to access that at www.example.com/posts/foobar.
Warning: You may be tempted to name your controllers and actions a certain way to obtain a certain
URL. Resist that temptation. Follow CakePHP conventions (capitalization, plural names, etc.) and create
readable, understandable action names. You can map URLs to your code using “routes” covered later
on.
The single instruction in the action uses set() to pass data from the controller to the view (which we’ll
create next). The line sets the view variable called ‘posts’ equal to the return value of the find(’all’)
method of the Post model. Our Post model is automatically available at $this->Post because we’ve
followed CakePHP’s naming conventions.
To learn more about CakePHP’s controllers, check out the Controllers chapter.

Creating Post Views
Now that we have our data flowing to our model, and our application logic and flow defined by our controller,
let’s create a view for the index action we created above.
CakePHP views are just presentation-flavored fragments that fit inside an application’s layout. For most
applications, they’re HTML mixed with PHP, but they may end up as XML, CSV, or even binary data.
A layout is presentation code that is wrapped around a view. Multiple layouts can be defined, and you can
switch between them, but for now, let’s just use the default.
Remember how in the last section we assigned the ‘posts’ variable to the view using the set() method?
That would pass data to the view that would look something like this:
// print_r($posts) output:
Array
(
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => The title
[body] => This is the post body.
[created] => 2008-02-13 18:34:55
[modified] =>
)
)
[1] => Array
(
[Post] => Array
(
[id] => 2
[title] => A title once again
[body] => And the post body follows.

Blog Tutorial - Adding a layer

11

CakePHP Cookbook Documentation, Release 2.x

[created] => 2008-02-13 18:34:56
[modified] =>
)
)
[2] => Array
(
[Post] => Array
(
[id] => 3
[title] => Title strikes back
[body] => This is really exciting! Not.
[created] => 2008-02-13 18:34:57
[modified] =>
)
)
)

CakePHP’s view files are stored in /app/View inside a folder named after the controller to which they
correspond. (We’ll have to create a folder named ‘Posts’ in this case.) To format this post data into a nice
table, our view code might look something like this
<!-- File: /app/View/Posts/index.ctp -->
<h1>Blog posts</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!-- Here is 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 $this->Html->link($post['Post']['title'],
array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
<?php unset($post); ?>
</table>

You might have noticed the use of an object called $this->Html. This is an instance of the CakePHP
HtmlHelper class. CakePHP comes with a set of view helpers that make things like linking, form output,
JavaScript and AJAX a snap. You can learn more about how to use them in Helpers, but what’s important to
note here is that the link() method will generate an HTML link with the given title (the first parameter)
and URL (the second parameter).
When specifying URLs in CakePHP, it is recommended that you use the array format. This is explained

12

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

in more detail in the section on Routes. Using the array format for URLs allows you to take advantage of
CakePHP’s reverse routing capabilities. You can also specify URLs relative to the base of the application in
the form of /controller/action/param1/param2.
At this point, you should be able to point your browser to http://www.example.com/posts/index. You should
see your view, correctly formatted with the title and table listing of the posts.
If you happened to have clicked on one of the links we created in this view (which link a post’s title to a URL
/posts/view/some_id), you were probably informed by CakePHP that the action hadn’t yet been defined. If
you were not so informed, either something has gone wrong, or you actually did define it already, in which
case you are very sneaky. Otherwise, we’ll create it in the PostsController now:
// File: /app/Controller/PostsController.php
class PostsController extends AppController {
public $helpers = array('Html', 'Form');
public function index() {
$this->set('posts', $this->Post->find('all'));
}
public function view($id = null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$post = $this->Post->findById($id);
if (!$post) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('post', $post);
}
}

The set() call should look familiar. Notice we’re using findById() rather than find(’all’) because we only want a single post’s information.
Notice that our view action takes a parameter: the ID of the post we’d like to see. This parameter is handed
to the action through the requested URL. If a user requests /posts/view/3, then the value ‘3’ is passed
as $id.
We also do a bit of error checking to ensure that a user is actually accessing a record. If a user requests
/posts/view, we will throw a NotFoundException and let the CakePHP ErrorHandler take over.
We also perform a similar check to make sure the user has accessed a record that exists.
Now let’s create the view for our new ‘view’ action and place it in /app/View/Posts/view.ctp
<!-- File: /app/View/Posts/view.ctp -->
<h1><?php echo h($post['Post']['title']); ?></h1>
<p><small>Created: <?php echo $post['Post']['created']; ?></small></p>
<p><?php echo h($post['Post']['body']); ?></p>

Blog Tutorial - Adding a layer

13

CakePHP Cookbook Documentation, Release 2.x

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 a great start, but let’s allow for adding new posts.
First, start by creating an add() action in the PostsController:
class PostsController extends AppController {
public $helpers = array('Html', 'Form', 'Flash');
public $components = array('Flash');
public function index() {
$this->set('posts', $this->Post->find('all'));
}
public function view($id) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$post = $this->Post->findById($id);
if (!$post) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('post', $post);
}
public function add() {
if ($this->request->is('post')) {
$this->Post->create();
if ($this->Post->save($this->request->data)) {
$this->Flash->success(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
$this->Flash->error(__('Unable to add your post.'));
}
}
}

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

Note: You need to include the FlashComponent - and FlashHelper - in any controller where you will use
it. If necessary, include it in your AppController.
Here’s what the add() action does: if the HTTP method of the request was POST, it tries to save the data
using the Post model. If for some reason it doesn’t save, it just renders the view. This gives us a chance to

14

Chapter 1. Getting Started

CakePHP Cookbook Documentation, Release 2.x

show the user validation errors or other warnings.
Every CakePHP request includes a CakeRequest object which is accessible using $this->request.
The request object contains useful information regarding the request that was just received, and can be used
to control the flow of your application. In this case, we use the CakeRequest::is() method to check
that the request is a HTTP POST request.
When a user uses a form to POST data to your application, that information is available in
$this->request->data. You can use the pr() or debug() functions to print it out if you want
to see what it looks like.
We use the FlashComponent’s FlashComponent::success() method to set a message to a session
variable to be displayed on the page after redirection. In the layout we have FlashHelper::render()
which displays the message and clears the corresponding session variable.
The controller’s
Controller::redirect function redirects to another URL. The param array(’action’ =>
’index’) translates to URL /posts (that is, the index action of the posts controller). You can refer to
Router::url() function on the API7 to see the formats in which you can specify a URL for various
CakePHP functions.
Calling the save() method will check for validation errors and abort the save if any occur. We’ll discuss
how those errors are handled in the following sections.
We call the create() method first in order to reset the model state for saving new information. It does not
actually create a record in the database, but clears Model::$id and sets Model::$data based on your database
field defaults.

Data Validation
CakePHP goes a long way toward taking the monotony out of form input validation. Everyone hates coding
up endless forms and their validation routines. CakePHP makes it easier and faster.
To take advantage of the validation features, you’ll need to use CakePHP’s FormHelper in your views. The
FormHelper is available by default to all views at $this->Form.
Here’s our add view:
<!-- File: /app/View/Posts/add.ctp -->
<h1>Add Post</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->end('Save Post');
?>

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

Here’s the HTML that

<form id="PostAddForm" method="post" action="/posts/add">
7

http://api.cakephp.org

Blog Tutorial - Adding a layer

15

CakePHP Cookbook Documentation, Release 2.x

If create() is called with no parameters supplied, it assumes you are building a form that submits via
POST to the current controller’s add() action (or edit() action when id is included in the form data).
The $this->Form->input() method is used to create form elements of the same name. The first
parameter tells CakePHP which field they correspond to, and the second parameter allows you to specify a
wide array of options - in this case, the number of rows for the textarea. There’s a bit of introspection and
automagic here: input() will output different form elements based on the model field specified.
The $this->Form->end() call generates a submit button and ends the form. If a string is supplied as
the first parameter to end(), the FormHelper outputs a submit button named accordingly along with the
closing form tag. Again, refer to Helpers for more on helpers.
Now let’s go back and update our /app/View/Posts/index.ctp view to include a new “Add Post”
link. Before the <table>, add the following line:
<?php echo $this->Html->link(
'Add Post',
array('controller' => 'posts', 'action' => 'add')
); ?>

You may be wondering: how do I tell CakePHP about my validation requirements? Validation rules are
defined in the model. Let’s look back at our Post model and make a few adjustments:
class Post extends AppModel {
public $validate = array(
'title' => array(
'rule' => 'notBlank'
),
'body' => array(
'rule' => 'notBlank'
)
);
}

The $validate array tells CakePHP how to validate your data when the save() method is called. Here,
I’ve specified that both the body and title fields must not be empty. CakePHP’s validation engine is strong,
with a number of pre-built rules (credit card numbers, email addresses, etc.) and flexibility for adding your
own validation rules. For more information, check the Data Validation.
Now that you have your validation rules in place, use the app to try to add a post with an empty title or body
to see how it works. Since we’ve used the FormHelper::input() method of the FormHelper to create
our form elements, our validation error messages will be shown automatically.

Editing Posts
Post editing: here we go. You’re a CakePHP 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 PostsController would look like:
public function edit($id = null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}

16

Chapter 1. Getting Started

} $this->Flash->error(__('Unable to update your post.File: /app/View/Posts/index. } } This action first ensures that the user has tried to access an existing record. } if (!$this->request->data) { $this->request->data = $post. 'put'))) { $this->Post->id = $id.File: /app/View/Posts/edit. ?> This view outputs the edit form (with the values populated). Next the action checks whether the request is either a POST or a PUT request. One thing to note here: CakePHP will assume that you are editing a model if the ‘id’ field is present in the data array.x $post = $this->Post->findById($id). along with any necessary validation error messages. If no ‘id’ is present (look back at our add view).')). if (!$post) { throw new NotFoundException(__('Invalid post')). ?></p> Blog Tutorial .ctp --> <h1>Edit Post</h1> <?php echo $this->Form->create('Post'). echo $this->Form->input('body'. echo $this->Form->input('id'. if ($this->Post->save($this->request->data)) { $this->Flash->success(__('Your post has been updated. array('type' => 'hidden')). If there is no data set to $this->request->data. echo $this->Form->end('Save Post').')). or kick back and show the user validation errors. echo $this->Form->input('title'). return $this->redirect(array('action' => 'index')).ctp (edit links added) --> <h1>Blog posts</h1> <p><?php echo $this->Html->link("Add Post". we simply set it to the previously retrieved post. or the post does not exist. we throw a NotFoundException for the CakePHP ErrorHandler to take care of. If they haven’t passed in an $id parameter. then we use the POST data to update our Post record. CakePHP 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: <!-. The edit view might look something like this: <!-. array('rows' => '3')).Adding a layer 17 . If it is. array('action' => 'add')).CakePHP Cookbook Documentation. Release 2. } if ($this->request->is(array('post'.

h($id)) ). ?> </table> Deleting Posts Next.x <table> <tr> <th>Id</th> <th>Title</th> <th>Action</th> <th>Created</th> </tr> <!-. Start with a delete() action in the PostsController: public function delete($id) { if ($this->request->is('get')) { throw new MethodNotAllowedException().'. } else { $this->Flash->error( 18 Chapter 1. let’s make a way for users to delete posts. array('action' => 'edit'. ?> </td> <td> <?php echo $post['Post']['created']. array('action' => 'view'. ?> </td> </tr> <?php endforeach. Release 2. ?> </td> <td> <?php echo $this->Html->link( 'Edit'. $post['Post']['id']) ).Here's where we loop through our $posts array.CakePHP Cookbook Documentation. Getting Started . printing out post info --> <?php foreach ($posts as $post): ?> <tr> <td><?php echo $post['Post']['id']. } if ($this->Post->delete($id)) { $this->Flash->success( __('The post with id: %s has been deleted. ?></td> <td> <?php echo $this->Html->link( $post['Post']['title']. $post['Post']['id']) ).

Because we’re just executing some logic and redirecting.x __('The post with id: %s could not be deleted. If the user attempts to do a delete using a GET request. printing out post info --> <?php foreach ($posts as $post): ?> <tr> <td><?php echo $post['Post']['id']. } return $this->redirect(array('action' => 'index')). $post['Post']['id']) ). array('action' => 'view'.'. } This logic deletes the post specified by $id. $post['Post']['id']) ). array('confirm' => 'Are you sure?') ). and a nice error page is displayed. and uses $this->Flash->success() to show the user a confirmation message after redirecting them on to /posts. array('action' => 'delete'.ctp --> <h1>Blog posts</h1> <p><?php echo $this->Html->link('Add Post'. There are many built-in Exceptions that can be used to indicate the various HTTP errors your application might need to generate. array('action' => 'add')). ?></p> <table> <tr> <th>Id</th> <th>Title</th> <th>Actions</th> <th>Created</th> </tr> <!-. ?> <?php echo $this->Html->link( 'Edit'.File: /app/View/Posts/index. ?></td> <td> <?php echo $this->Html->link( $post['Post']['title'].Adding a layer 19 . Release 2. Uncaught exceptions are captured by CakePHP’s exception handler. ?> </td> <td> <?php echo $this->Form->postLink( 'Delete'. array('action' => 'edit'. You might want to update your index view with links that allow users to delete posts. however: <!-. we throw an Exception.CakePHP Cookbook Documentation. this action has no view. h($id)) ). Blog Tutorial . $post['Post']['id']).Here's where we loop through our $posts array.

Allowing content to be deleted using GET requests is dangerous. For more information on advanced routing techniques. We want it to connect with our own controller. 'home') ). array('controller' => 'posts'. Developers who are sensitive to user-friendliness and general search engine compatibility will appreciate the way that CakePHP’s URLs map to specific actions. we’ll replace this with our PostsController by creating a routing rule..php. Release 2. If. and also ensures that links point to the same place. This line connects the URL ‘/’ with the default CakePHP home page. CakePHP’s routing is found in /app/Config/routes. Getting Started .g.com) using its PagesController. http://www. rendering a view called “home”. 'action' => 'display'. This should connect users requesting ‘/’ to the index() action of our PostsController. ’action’ => ’index’) to a function expecting an array. CakePHP responds to a request for the root of your site (e. Instead. CakePHP’s default routing works well enough. the resulting URL used will be ‘/’.CakePHP Cookbook Documentation. Note: CakePHP also makes use of ‘reverse routing’. Routes For some. so replace that line with this one: Router::connect('/'. ?> </td> </tr> <?php endforeach. Note: This view code also uses the FormHelper to prompt the user with a JavaScript confirmation dialog before they attempt to delete a post.x ?> </td> <td> <?php echo $post['Post']['created']. as web crawlers could accidentally delete all your content. as this means your routes define where a URL goes. It’s therefore a good idea to always use arrays for URLs.example. 'action' => 'index')). It looks like this: Router::connect( '/'. By default. ?> </table> Using postLink() will create a link that uses JavaScript to do a POST request to delete our post. with the above route defined. array('controller' => 'pages'. So we’ll just make a quick change to routes in this tutorial. You’ll want to comment out or remove the line that defines the default root route. you pass array(’controller’ => ’posts’. see Routes Configuration. 20 Chapter 1.

and his browser makes a request to your web server. so let’s look at how objects work together to complete a basic request.x Conclusion Creating applications this way will win you peace. If you need help. Layouts: Customizing your website layout 2. Scaffolding: Prototyping before creating code 4. 3. Figure: 2.com/cakes/buy. and is flexible in ways we didn’t wish to cover here for simplicity’s sake. and any other arguments that will affect the business logic during this request. and money beyond even your wildest fantasies. Black = required element.example. CakePHP has many more features to offer. 8 http://api. 2. Ricardo clicks the link pointing to http://www. Continuing with our original request example. Typical CakePHP Request. Gray = optional element. Welcome to CakePHP! Suggested Follow-up Reading These are common tasks people learning CakePHP usually want to study next: 1. love. let’s imagine that our friend Ricardo just clicked on the “Buy A Custom Cake Now!” link on a CakePHP application’s landing page. The controller’s beforeFilter() callback is called before any controller action logic is executed. Simple Authentication and Authorization Application: User authentication and authorization tutorial Additional Reading A Typical CakePHP Request We’ve covered the basic ingredients in CakePHP. Blue = callback 1. it’s the buy() method of the CakesController.org Blog Tutorial .please see the Where to Get Help page. Start your own project and read the rest of the Cookbook and API8 . isn’t it? Keep in mind that this tutorial was very basic. Using routes. Code Generation with Bake: Generating basic CRUD code 5. a request URL is mapped to a controller action (a method in a specific controller class). there are many ways to get the help you need . In this case. you’re ready for the real thing. Use the rest of this manual as a guide for building more feature-rich applications. Now that you’ve created a basic CakePHP application. Elements: Including and reusing view snippets 3. Simple.CakePHP Cookbook Documentation. The Router parses the URL in order to extract the parameters for this request: the controller. action. honor. Release 2.Adding a layer 21 .cakephp.

x Figure 1. Release 2.CakePHP Cookbook Documentation. Getting Started .1: Flow diagram showing a typical CakePHP request 22 Chapter 1.

CamelCased. the default CakePHP behavior is to execute the index() method of that controller. 5. } protected function _findNewArticles() { Blog Tutorial . CakePHP Conventions We are big fans of convention over configuration. whereas http://www.Adding a layer 23 . for example). it is returned to the controller.example. The first method you write for a controller might be the index() method. you get free functionality. 8. By default. After the model has retrieved the data. For example: class NewsController extends AppController { public function latest() { $this->_findNewArticles().com/apples/view/ maps to a call on the view() method of the ApplesController. the view is rendered inside a layout. CakePHP’s conventions have been distilled from years of web development experience and best practices. While model usage is not required. you save time in the long run: by following convention. rendered view code is sent to Ricardo’s browser. Controller callbacks may be applied before the data is sent. Convention also makes for a very uniform system development. the method will not be accessible directly from the web but is available for internal use.com/apples/ maps to a call on the index() method of the ApplesController. While it takes a bit of time to learn CakePHP’s conventions. allowing other developers to jump in and help more easily. Once the controller has used models and components to prepare the data sufficiently.example. You can also change the visibility of controller methods in CakePHP by prefixing controller method names with underscores. Release 2. The complete. or sending emails. The controller may use components to further refine the data or perform other operations (session manipulation. a request for http://www. which may include the use of elements and/or helpers. and DataSources may apply during this operation. 6. The controller may use models to gain access to the application’s data. that data is handed to the view using the controller’s set() method. PeopleController and LatestArticlesController are both examples of conventional controller names. and end in Controller. While we suggest you use these conventions while developing with CakePHP. all CakePHP controllers initially require at least one model. For example. Controller Conventions Controller class names are plural. When a request specifies a controller but not an action. Model callbacks may apply.CakePHP Cookbook Documentation. Any applicable model callbacks. 7. behaviors. authentication. Additional controller callbacks (like afterFilter) may be applied. If a controller method has been prefixed with an underscore. we should mention that many of these tenets are easily overridden – something that is especially handy when working with legacy systems. and you free yourself from the maintenance nightmare of tracking config files.x 4. The view logic is performed. In this example. the controller uses a model to fetch Ricardo’s last purchases from the database.

php • The Behavior class EspeciallyFunkableBehavior would be found in a file named EspeciallyFunkableBehavior. So if you have a class MyNiftyClass. which are CamelCased. Non-public methods cannot be accessed.php.php • The Component class MyHandyComponent would be found in a file named MyHandyComponent.example. Release 2. you will be directed to the file/directory and. therefore /red_apples/go_pick is the correct form to access the RedApplesController::go_pick action. someone trying to get to the page http://www. For example. File and Class Name Conventions In general. because the method is preceded with an underscore.CakePHP Cookbook Documentation.php Each file would be located in the appropriate folder in your app folder. filenames match the class names. Below are examples of how to name the file for each of the different types of classes you would typically use in a CakePHP application: • The Controller class KissesAndHugsController would be found in a file named KissesAndHugsController. If you have files/directories in your /webroot directory that share a name with one of your routes/controllers.example.php • The View class SuperSimpleView would be found in a file named SuperSimpleView.php • The Helper class BestEverHelper would be found in a file named BestEverHelper. For more information on CakePHP URLs and parameter handling. Getting Started .x // Logic to find latest news articles } } While the page http://www. not to your controller. URL Considerations for Controller Names As you’ve just seen.com/apples. see Routes Configuration.com/news/_findNewArticles/ would get an error. 24 Chapter 1. ApplesController (which would be defined in the file name ‘ApplesController.php’) is accessed from http://example. the convention is that your URLs are lowercase and underscored. then in CakePHP. You can also use PHP’s visibility keywords to indicate whether or not a method can be accessed from a URL. the file should be named MyNiftyClass. However. Multiple word controllers can be any ‘inflected’ form which equals the controller name so: • /redApples • /RedApples • /Red_apples • /red_apples will all resolve to the index of the RedApples controller.php • The Model class OptionValue would be found in a file named OptionValue.com/news/latest/ would be accessible to the user as usual. single word controllers map easily to a simple lower case URL path.

The getReady() function of the PeopleController class will look for a view template in /app/View/People/get_ready.ctp. must be named after the model tables they will join. CakePHP will then use a unique 36 character UUID (String::uuid) whenever you save a new record using the Model::save method.primaryKey attribute. By naming the pieces of your application using CakePHP conventions. big_people. Rather than using an auto-increment key as the primary key. You must add a single-field primary key if you want to use that table’s model. then you must set the Model. and ReallyBigPerson are all examples of conventional model names. in an underscored form. All tables with which CakePHP models interact (with the exception of join tables) require a singular primary key to uniquely identify each row. BigPerson. Foreign keys in hasMany. e.ctp. Here’s a final example that ties the conventions together: Blog Tutorial . the cakes table will refer to the bakers table via a baker_id foreign key. Release 2.x Model and Database Conventions Model class names are singular and CamelCased. post_id INT(10) NOT NULL. CakePHP does not support composite primary keys. tag_id INT(10) NOT NULL. If primary key’s name is not id. use direct query calls or add a primary key to act on it as a normal model. If you wish to model a table that does not already have a single-field primary key. and really_big_people. you gain functionality without the hassle and maintenance tethers of configuration. the foreign key would be category_type_id.CakePHP Cookbook Documentation. The basic pattern is /app/View/Controller/underscored_function_name. If you want to directly manipulate your join table data. CakePHP’s convention is that a single-field primary key is added to the table. respectively. For a table like category_types whose name contains multiple words. The underlying tables for the above mentioned models would be people. used in hasAndBelongsToMany (HABTM) relationships between models. Join tables.Adding a layer 25 . users HABTM groups would be joined by groups_users. apes_zoos is better than zoos_apes. You can use the utility library Inflector to check the singular/plural of words. See the Inflector for more information. belongsTo or hasOne relationships are recognized by default as the (singular) name of the related table followed by _id. Table names corresponding to CakePHP models are plural and underscored. View Conventions View template files are named after the controller functions they display. For example: CREATE TABLE posts_tags ( id INT(10) NOT NULL AUTO_INCREMENT. and should be arranged in alphabetical order. So if a Baker hasMany Cake.g. PRIMARY KEY(id) ). Field names with two or more words are underscored: first_name. you may also use char(36). Person.g. e.

• Finally. these are the files and folders you should see: • app • lib • vendors • plugins • .ctp Using these conventions. Release 2.x • Database table: “people” • Model class: “Person”.php • View template.com/people/ maps to a call on the index() function of the PeopleController. Now that you’ve been introduced to CakePHP’s fundamentals. 26 Chapter 1. Make a personal commitment not to edit files in this folder. Getting Started . None of these relationships have been configured by any means other than by creating classes and files that you’d need to create anyway. Database connection details. look into modifying Application Extensions. CakePHP knows that a request to http://example. bootstrapping. The App Folder CakePHP’s app folder is where you will do most of your application development. Config Holds the (few) configuration files CakePHP uses. CakePHP Folder Structure After you’ve downloaded and extracted CakePHP. We can’t help you if you’ve modified the core.php • README You’ll notice three main folders: • The app folder will be where you work your magic: it’s where your application’s files will be placed. found at /app/Model/Person. and renders to a file. core configuration files and more should be stored here. Instead.CakePHP Cookbook Documentation. • The lib folder is where we’ve worked our magic. found at /app/Controller/PeopleController. you might try a run through the /tutorials-and-examples/blog/blog to see how things fit together.php • Controller class: “PeopleController”. found at /app/View/People/index. where the Person model is automatically available (and automatically tied to the ‘people’ table in the database). Let’s look a little closer at the folders inside app.htaccess • index. the vendors folder is where you’ll place third-party PHP libraries you need to use with your CakePHP applications.

This allows you to separate your organization’s internal libraries from vendor libraries. Vendor Any third-party classes or libraries should be placed here. Plugin Contains plugin packages. webroot In a production setup. and View classes. Keen observers will note that this seems redundant. images. Make sure that this folder exists and is writable. Application Extensions Controllers. Controller Contains your application’s controllers and their components. CakePHP will warn you if the folder is absent or not writable. and view files. layouts. Test This directory contains all the test cases and test fixtures for your application. For more information see Shells. Lib Contains libraries that do not come from 3rd parties or external vendors. We’ll get into the differences between the two when we discuss managing multiple applications and more complex system setups. refer to the Testing documentation. helpers. behaviors. Release 2. View Presentational files are placed here: elements. Behaviors.php) are great places to put methods you want to share between all controllers. For more information on test cases and test fixtures.CakePHP Cookbook Documentation. and sometimes session information. this folder should serve as the document root for your application. Folders here also serve as holding places for CSS stylesheets. tmp This is where CakePHP stores temporary data. so look for the details on how to use these tools later on.php) and AppModel (located at /app/Model/AppModel.x Console Contains the console commands and console tasks for your application. but this folder is usually used to store model descriptions. Tasks & Console Tools. Right now we’ll stay at a higher level. AppController (located at /app/Controller/AppController. Blog Tutorial . helpers and models each have a parent class you can use to define applicationwide changes. error pages. AppHelper (located at /app/View/Helper/AppHelper. Model Contains your application’s models. CakePHP Structure CakePHP features Controller. as there is also a vendors folder at the top level of our directory structure. Locale Stores string files for internationalization. In debug mode. and datasources. ‘name’) function.php). or the performance of your application will be severely impacted. Doing so makes them easy to access using the App::import(‘vendor’.Adding a layer 27 . and JavaScript files. Components. and Helpers are classes that provide extensibility and reusability to quickly add functionality to the base MVC classes in your applications. The Test/Case directory should mirror your application and contain one or more test cases per class in your application. Model. logs. The actual data it stores depends on how you have CakePHP configured. helpers or models. but it also features some additional classes and objects that make development in MVC a little quicker and more enjoyable. This directory can also contain a Templates directory to customize the output of bake.

adding. Like controllers. and shifting nodes in your underlying tree structure. executed after all controller logic. Route definitions tell CakePHP how to map URLs to controller actions. As an example. Controller Extensions (“Components”) A Component is a class that aids in controller logic. A plugin is a package of models. CSV files. DataSources are an abstraction that enable models to manipulate different types of data consistently. but before the view is rendered Model Extensions (“Behaviors”) Similarly. DataSources allow you to tell your LDAP model that it is associated with many iCal events. Models are also supported by another class called a DataSource. Getting Started . A user management system or a simplified blog might be a good fit for CakePHP plugins. Behaviors work as ways to add common functionality between models. a component is usually a good fit. The default behavior assumes that the URL /controller/action/var1/var2 maps to Controller::action($var1. LDAP entries. but you can use routes to customize URLs and how they are interpreted by your application. Rather than writing a controller method in a single controller that performs this logic. While the main source of data in a CakePHP application is often a database. they play a role in requests made to CakePHP. Release 2. $var2). DataSources allow you to associate records from different sources: rather than being limited to SQL joins. Some features in an application merit packaging as a whole. if you store user data in a tree structure. the core EmailComponent class makes creating and sending emails a snap.x Although routes aren’t classes or files. models have callbacks: • beforeFind() • afterFind() • beforeValidate() • afterValidate() • beforeSave() • afterSave() • beforeDelete() 28 Chapter 1. If you have some logic you want to share between controllers (or applications). you can package the logic so it can be shared. controllers and views that accomplishes a specific purpose that can span multiple applications. you might write additional DataSources that allow your models to represent RSS feeds. or iCal events. These callbacks are available for your use. including the rendering of the view • beforeFilter().CakePHP Cookbook Documentation. Controllers are also fitted with callbacks. executed after controller logic. you can specify your User model as behaving like a tree. executed before any controller action logic • beforeRender(). and gain free functionality for removing. just in case you need to insert some logic between CakePHP’s core operations. For example. Callbacks available include: • afterFilter().

every view rendered by a controller is placed inside a layout. Most applications have pieces of view code that are used repeatedly. helpers allow presentational logic to be accessed and shared between views. Blog Tutorial . One of the core helpers. Elements are used when small snippets of content need to be reused in multiple views. You can find the details in the models chapter. Much like a component used among controllers. View Extensions (“Helpers”) A Helper is a class that aids in view logic.CakePHP Cookbook Documentation. CakePHP facilitates view code reuse with layouts and elements. JsHelper. makes AJAX requests within views much easier and comes with support for jQuery (default).x • afterDelete() The names of these methods should be descriptive enough to let you know what they do.Adding a layer 29 . Prototype and Mootools. Release 2. By default.

Getting Started . Release 2.CakePHP Cookbook Documentation.x 30 Chapter 1.

• PHP 5.2. 31 . but by no means required. Requirements • HTTP Server. You should make sure you have the correct PDO extensions installed.6 and below support PHP 5. that’s it! While this manual focuses primarily on setting up on Apache (because it’s the most commonly used). License CakePHP is licensed under the MIT license. mod_rewrite is preferred. you can configure CakePHP to run on a variety of web servers such as lighttpd or Microsoft IIS.0 or greater (CakePHP version 2. For example: Apache.CHAPTER 2 Installation CakePHP is fast and easy to install. You are also free to incorporate CakePHP into any commercial or closed source application. distribute and republish the source code on the condition that the copyright notices are left intact. Technically a database engine isn’t required. but we imagine that most applications will utilize one.8 and above).3. This means that you are free to modify. CakePHP supports a variety of database storage engines: • MySQL (4 or greater) • PostgreSQL • Microsoft SQL Server • SQLite Note: All built-in drivers require PDO. The minimum requirements are a webserver and a copy of CakePHP.

As such. or check out the code from the git repository.com/cakephp/cakephp. Release 2.com/cakephp/cakephp 2 32 Chapter 2.x Downloading CakePHP There are two main ways to get a fresh copy of CakePHP. clean URLs. To download the latest major release of CakePHP. with all the bug-fixes and up to the minute enhancements.bz2) from the main website. 1 http://github. URLs for the application include the CakePHP installation directory name.org and follow the “Download” link. you can run the following commands just once in your project to ensure that permissions will be setup properly: HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | h setfacl -R -m u:${HTTPDUSER}:rwx app/tmp setfacl -R -d -m u:${HTTPDUSER}:rwx app/tmp Setup Setting up CakePHP can be as simple as slapping it in your web server’s document root. GitHub houses both CakePHP itself as well as many other plugins for CakePHP. On a UNIX system. You can either download an archived copy (zip/tar.git Permissions CakePHP uses the app/tmp directory for a number of different operations. This section will cover the three main installation types for CakePHP: development. • Development: easy to get going. All current releases of CakePHP are hosted on GitHub1 .gz/tar. make sure the directory app/tmp and all its subdirectories in your CakePHP installation are writable by the web server user.x git://github. These can be accessed from GitHub by cloning the GitHub3 repository: git clone -b 2. • Production: Requires the ability to configure the web server’s document root.com/cakephp/cakephp/tags 3 http://github.CakePHP Cookbook Documentation. and advanced.com/cakephp/cakephp https://github. production. Installation . if your web server user is different from your command line user. visit the main website http://cakephp. The CakePHP releases are available at GitHub tags2 . One common issue is that the app/tmp directories and subdirectories must be writable both by the web server and the command line user. or as complex and flexible as you wish. Alternatively you can get fresh off the press code. A few examples would be Model descriptions. very secure. cached views and session information. and less secure.

Your development setup will look like this on the file system: /var/www/html/ cake_2_0/ app/ lib/ plugins/ vendors/ .0). instead of : Development 33 .x • Advanced: With some configuration. Using one CakePHP Checkout for multiple Applications If you are developing a number of applications. you should now find your CakePHP application accessible at http://www. This example will help you install a CakePHP application and make it available at http://www. On *nix systems this is often in /etc/php.git /home/mark/projects/cakephp This will clone CakePHP into your /home/mark/projects directory. possibly sharing a single CakePHP core library folder amongst many CakePHP applications.com/cake_2_0/. separate include paths with . You now have a folder in your document root named after the release you’ve downloaded (e. cake_2. Rename this folder to cake_2_0. we’ll use /home/mark/projects: git clone git://github.htaccess index. If you don’t want to use git. but using php -i and looking for ‘Loaded Configuration File’. Next you’ll have to locate and modify your php.com/cakephp/cakephp. Once you’ve found the correct ini file. For this example. modify the include_path configuration to include /home/mark/projects/cakephp/lib.ini. Often the easiest is to use PHP’s include_path.:/home/mark/projects/cakephp/lib:/usr/local/php/lib/php After restarting your webserver. We assume for the purposes of this example that your document root is set to /var/www/html. To start off.example. you can download a zipball and the remaining steps will be the same. clone CakePHP into a directory.0. There are a few ways in which you can accomplish this. Development A development installation is the fastest method to setup CakePHP. Unpack the contents of the CakePHP archive into /var/www/html.php README If your web server is configured correctly. Release 2. you should see the changes reflected in phpinfo().ini. An example would look like: include_path = . you can find the actual location. Note: If you are on Windows.g.CakePHP Cookbook Documentation.com/cake_2_0/. allows you to place key CakePHP directories in different parts of the filesystem. it often makes sense to have them share the same CakePHP core checkout.example.

Installing with the PEAR installer can simplify sharing CakePHP libraries across multiple applications.com.cakephp. Release 2. we assume you chose to install CakePHP into /cake_install.example. Your production setup will look like this on the filesystem: /cake_install/ app/ webroot/ (this directory is set as the ``DocumentRoot`` directive) lib/ plugins/ vendors/ .php README Developers using Apache should set the DocumentRoot directive for the domain to: DocumentRoot /cake_install/app/webroot If your web server is configured correctly. Advanced Installation and URL Rewriting Advanced Installation Installing CakePHP with PEAR Installer CakePHP publishes a PEAR package that you can install using the PEAR installer.org pear install cakephp/CakePHP Note: On some systems installing libraries with PEAR will require sudo. For the purposes of this example. This example will help you install CakePHP anywhere on your filesystem and make it available at http://www. Note that this installation may require the rights to change the DocumentRoot on Apache webservers. 34 Chapter 2.CakePHP Cookbook Documentation.example.com. Unpack the contents of the CakePHP archive into a directory of your choice. Production A production installation is a more flexible way to setup CakePHP. you should now find your CakePHP application accessible at http://www.x Having finished setting up your include_path your applications should be able to find CakePHP automatically. To install CakePHP with PEAR you’ll need to do the following: pear channel-discover pear. Installation . Using this method allows an entire domain to act as a single CakePHP application.htaccess index.

Since CakePHP also publishes releases to Packagist.json Vendor/ bin/ autoload. Installing CakePHP with Composer Composer is a dependency management tool for PHP 5. "require": { "cakephp/cakephp": "2. changing CAKE_CORE_INCLUDE_PATH to be a relative path: 4 5 https://packagist. To make your application more portable you should modify webroot/index. Packagist4 is the main repository of Composer installable packages.json file for a CakePHP application would look like the following: { "name": "example-app". After you’ve downloaded Composer.*" }. Next download the composer. if PEAR is configured correctly you should be able to use the cake command to create a new application.org Advanced Installation and URL Rewriting 35 .x After installing CakePHP with PEAR.3+. Release 2.CakePHP Cookbook Documentation.json in the APP directory of your project.phar composer.php composer/ cakephp/ You are now ready to generate the rest of your application skeleton: $ Vendor/bin/cake bake project <path to project> By default bake will hard-code CAKE_CORE_INCLUDE_PATH.json run the following: $ php composer. you can install CakePHP using Composer5 .phar file into your project. It solves many of the problems the PEAR installer has. In the same directory as your composer. "config": { "vendor-dir": "Vendor/" } } Save this JSON into composer.org/ http://getcomposer.phar install Once Composer has finished running you should have a directory structure that looks like: example-app/ composer. Since CakePHP will be located on PHP’s include_path you won’t need to make any other changes. Before installing CakePHP you’ll need to setup a composer. and simplifies managing multiple versions of libraries. A composer.php.json file.8. install CakePHP.

DS . • APP_DIR should be set to the (base)name of your app folder. You should now have a functioning CakePHP application installed via Composer. The application’s webroot. APP_DIR . which needs to be accessible by your web server. To configure your CakePHP installation. Be sure to keep the composer. This section describes how to spread your CakePHP directories across a filesystem. in /lib/Cake. 'load')). DS . 'load'). Installation .x define( 'CAKE_CORE_INCLUDE_PATH'. // See: http://goo. require APP . realize that there are three main parts to a CakePHP application: 1. or maybe you just want a few of your apps to share the same CakePHP libraries. // Remove and re-prepend CakePHP's autoloader as Composer thinks it is the // most important.php • /app/webroot/test. DS . You can even move the webroot folder out of the app folder as long as you tell CakePHP where you’ve put it.php'. 'cakephp' . 'Vendor/autoload. and CAKE_CORE_INCLUDE_PATH. 3. in /app. Note: If you are planning to create unit tests for your application you’ll also need to make the above change to webroot/test.CakePHP Cookbook Documentation. Each of these directories can be located anywhere on your file system. DS . • ROOT should be set to the path of the directory that contains your app folder. 'cakephp' . 'lib' ).lock file with the rest of your source code. true). APP_DIR. you’ll need to setup the autoloader.php If you’re installing any other libraries with Composer. In your Config/bootstrap.) There are three constants that you’ll need to edit: ROOT. with the exception of the webroot. 36 Chapter 2. you’ll need to make some changes to the following files. Release 2.json and composer. Your application code. • /app/webroot/index.php file add the following: // Load Composer autoload.php (if you use the Testing feature. This may be due to a shared host restriction. First. Sharing CakePHP Libraries with multiple Applications There may be some situations where you wish to place CakePHP’s directories on different places on the filesystem.gl/kKVJO7 spl_autoload_unregister(array('App'. The core CakePHP libraries. usually in /app/webroot. ROOT . and work around an issue in Composer’s autoloader. 'Vendor' . 2. spl_autoload_register(array('App'. DS . true.

Given this type of setup.org/httpd/DistrosDefaultLayout for further information. • My application’s app directory will be /home/me/myapp. 'myapp'). This prevents any missing file errors you might get as a result of using the wrong delimiter.htaccess) This section was moved to URL rewriting. DS . comments removed) if (!defined('ROOT')) { define('ROOT'.apache. (Make sure you are editing the system httpd. I would need to edit my webroot/index. 'usr' . DS . } if (!defined('APP_DIR')) { define ('APP_DIR'. Here are a few things you might try to get it running correctly.conf rather than a user. 'home' . 'lib').CakePHP Cookbook Documentation.php (partial. You may also take a look at http://wiki.) These files can vary between different distributions and Apache versions. DS .conf. DS . and it makes your code more portable. } if (!defined('CAKE_CORE_INCLUDE_PATH')) { define('CAKE_CORE_INCLUDE_PATH'.or site-specific httpd. Make sure that an . First look at your httpd. 1. URL Rewriting Apache and mod_rewrite (and .conf.php file (which will end up at /var/www/mysite/index. • My application’s webroot directory will be /var/www/mysite/. in this example) to look like the following: // /app/webroot/index.x • CAKE_CORE_INCLUDE_PATH should be set to the path of your CakePHP libraries folder.htaccess) While CakePHP is built to work with mod_rewrite out of the box–and usually does–we’ve noticed that a few users struggle with getting everything to play nicely on their systems.php. } It is recommended to use the DS constant rather than slashes to delimit file paths. Let’s run through an example so you can see what an advanced installation might look like in practice. Release 2. Apache and mod_rewrite (and . 'me'). You should see something similar to: Advanced Installation and URL Rewriting 37 .htaccess override is allowed and that AllowOverride is set to All for the correct DocumentRoot. Imagine that I wanted to set up CakePHP to work as follows: • The CakePHP core libraries will be placed in /usr/lib/cake.

Make sure you are loading mod_rewrite correctly.4 and above.CakePHP Cookbook Documentation. After you make changes.htaccess files are actually in the right directories.c> RewriteEngine on RewriteRule ^$ app/webroot/ [L] RewriteRule (. you need to modify the configuration file for your httpd. You should see something like: LoadModule rewrite_module libexec/apache2/mod_rewrite. # # First. by checking for .x # Each directory to which Apache has access can be configured with respect # to which services and features are allowed and/or disabled in that # directory (and its subdirectories). # <Directory /> Options FollowSymLinks AllowOverride All # Order deny. we configure the "default" to be a very restrictive set of # features.c> RewriteEngine on RewriteRule ^$ webroot/ RewriteRule (. Verify that your .so In many systems these will be commented out by default. Make sure your copy of CakePHP comes from the downloads section of the site or our Git repository. Release 2. restart Apache to make sure the settings are active.*) webroot/$1 </IfModule> 38 [L] [L] Chapter 2.*) app/webroot/$1 [L] </IfModule> CakePHP app directory (will be copied to the top directory of your application by bake): <IfModule mod_rewrite. so you may just need to remove the leading # symbols.’ as hidden and therefore won’t copy them.allow # Deny from all </Directory> For users having apache 2. 3. Some operating systems treat files that start with ‘. and has been unpacked correctly. redirects everything to your CakePHP app): <IfModule mod_rewrite. Installation . CakePHP root directory (must be copied to your document.htaccess files.conf or virtual host configuration to look like the following: <Directory /var/www/> Options FollowSymLinks AllowOverride All Require all granted </Directory> 2.

htaccess files CakePHP uses (/.htaccess.x CakePHP webroot directory (will be copied to your application’s web root by bake): <IfModule mod_rewrite. you should prevent invalid assets from being parsed by CakePHP. so for example. Please refer to Apache’s online documentation for more information.htaccess). your web server is actually being served from a user directory that already uses mod_rewrite. 4. edit the file /etc/apache2/sites-available/default (location is distributiondependent). and can include additional things that are not related to CakePHP. so you have: <Directory /> Options FollowSymLinks AllowOverride All </Directory> <Directory /var/www> Options Indexes FollowSymLinks MultiViews AllowOverride All Order Allow.php [QSA.Deny Allow from all </Directory> On Mac OSX. In this file. your webroot .*)$ index. ensure that AllowOverride None is changed to AllowOverride All.com/virtualhostx/ Advanced Installation and URL Rewriting 39 . /app/. On Ubuntu. Modify your webroot .c> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.htaccess.c> RewriteEngine On RewriteBase /path/to/cake/app RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(. /app/webroot/.htaccess file would look like: <IfModule mod_rewrite. another solution is to use the tool virtualhostx6 to make a Virtual Host to point to your folder. For many hosting services (GoDaddy. you’ll need to add RewriteBase statements to the .CakePHP Cookbook Documentation.com/~username/cakephp/).php [QSA.htaccess to something like: 6 http://clickontyler. This can be added to the same section with the RewriteEngine directive. If you are installing CakePHP into a user directory (http://example. Release 2. (Optional) To improve production setup. you might want to try modifying settings for Virtual Hosts.L] </IfModule> If your CakePHP site still has problems with mod_rewrite.*)$ index. or any other URL structure that already utilizes mod_rewrite.L] </IfModule> The details of those changes will depend on your setup. 1and1).

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name. you will have to modify this. server { listen 80.example.L] </IfModule> The above will simply prevent incorrect assets from being sent to index. access_log /var/www/example.com/log/access.com$1 permanent.php and instead display your webserver’s 404 page.php [QSA. so it is necessary to create those rewritten URLs in the site-available configuration.com.log. you will need PHP running as a FastCGI instance. or use the default built-in CakePHP 404 by adding an ErrorDocument directive: ErrorDocument 404 /404-not-found Pretty URLs on nginx nginx does not make use of .CakePHP Cookbook Documentation. Depending upon your setup. server_name www.*)$ index. include /etc/nginx/fastcgi_params. Release 2. index index. fastcgi_pass 127.0.htaccess files like Apache.0.log. } server { listen 80.com/log/error.com.*) http://example. } location ~ \.com/public/app/webroot/. but at the very least.x <IfModule mod_rewrite.php. location / { try_files $uri $uri/ /index.php?$args. rewrite ^(. Installation .php. error_log /var/www/example. } } 40 Chapter 2. server_name example.c> RewriteEngine On RewriteBase /path/to/cake/app RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_URI} !^/(app/webroot/)?(img|css|js)/(.1:9000. fastcgi_index index. # root directive should be global root /var/www/example.*)$ RewriteRule ^(.php$ { try_files $uri =404. Additionally you can create a matching HTML 404 page.

htaccess files.php?$args.1.config in your CakePHP root folder.iis.php" stopProcessing="true"> <match url="^test. try_files $new_uri $new_uri/ /$1/index. js.CakePHP Cookbook Documentation.ico)(.webServer> <rewrite> <rules> <rule name="Rewrite requests to test.microsoft.aspx?id=5747 10 http://www. favicon)" stopProcessing="true"> <match url="^(img|css|files|js|favicon.08 or download it directly (32-bit9 / 64-bit10 ). Release 2.sock. If you get 502 bad gateway error from above configuration.aspx?id=7435 8 Advanced Installation and URL Rewriting 41 .*)$" /> <action type="Rewrite" url="app/webroot/{R:1}{R:2}" 7 http://www. css.com/en-us/download/details.).x If for some exotic reason you cannot change your root directory and need to run your project from a subfolder like example. While there are add-ons that can add this support.php(. follow these steps: 1. location ~ ^/(subfolder)/(.. } Note: Recent configuration of PHP-FPM is set to listen to php-fpm socket instead of TCP port 9000 on address 127. files.. set $new_uri /$1/webroot/$2. php handling .*)? { index index.0. URL Rewrites on IIS7 (Windows hosts) IIS7 does not natively support .. Create a new file called web.*)$" ignoreCase="false" /> <action type="Rewrite" url="app/webroot/test. you can also import htaccess rules into IIS to use CakePHP’s native rewrites.php{R:1}" /> </rule> <rule name="Exclude direct access to app/webroot/*" stopProcessing="true"> <match url="^app/webroot/(.*)$" ignoreCase="false" /> <action type="None" /> </rule> <rule name="Rewrite routed access to assets(img.microsoft. Use Microsoft’s Web Platform Installer7 to install the URL Rewrite Module 2.com/web/downloads/platform..com/subfolder/... try replacing fastcgi_pass from TCP port to socket path (eg: fastcgi_pass unix:/var/run/php5-fpm.aspx http://www.php. 3.com/en-us/download/details. To do this. 2.config file.net/downloads/microsoft/url-rewrite 9 http://www. copy the following code into your new web. you will have to inject “/webroot” in each request.0" encoding="UTF-8"?> <configuration> <system.0. . <?xml version="1.microsoft. Using Notepad or any XML-safe editor.

config file is created with the correct IIS-friendly rewrite rules. JavaScipt.example.htaccess functions. and a message that tells you the status of your current database connection. Fire It Up Alright.com/ or http://www. make sure you’ve activated “mod_rewrite”.webServer> </configuration> Once the web.php" stopProcessing="true"> <match url="^(. Add a line: url.CakePHP Cookbook Documentation. CSS. In the lighttpd configuration. At this point. 42 Chapter 2. and rerouting should work correctly. CakePHP’s links.+))?$" => "/index.php" appendQueryString="true" /> </rule> </rules> </rewrite> </system.* Rewrite /index. you’ll be presented with CakePHP’s default home.php } I don’t / can’t use URL rewriting If you don’t want to or can’t use URL rewriting on your webserver.rewrite-if-not-file =( "^([^\?]*)(\?(. so you can remove all .com/cake_2_0/. Depending on which setup you used.*)$" ignoreCase="false" /> <action type="Rewrite" url="index. let’s see CakePHP in action. you should point your browser to http://example. Release 2.php?url=$1&$3" ) URL rewrite rules for Hiawatha The required UrlToolkit rule (for URL rewriting) to use CakePHP with Hiawatha is: UrlToolkit { ToolkitID = cakephp RequestURI exists Return Match . Installation . refer to the core configuration.htaccess files. URL-Rewriting on lighttpd Lighttpd does not support .x appendQueryString="false" /> </rule> <rule name="Rewrite requested file/folder to index. Congratulations! You are ready to create your first CakePHP application.

*/ date_default_timezone_set('UTC'). Fire It Up 43 .CakePHP Cookbook Documentation. Release 2.php: /** * Uncomment this line and correct your server timezone to fix * any date & time related errors.x Not working? If you’re getting timezone related errors from PHP uncomment one line in app/Config/core.

Installation .CakePHP Cookbook Documentation.x 44 Chapter 2. Release 2.

It provides you with all the tools you need to get started coding and what you need to get done: the logic specific to your application. friendly Official CakePHP discussion group 1 http://www.wikipedia.CHAPTER 3 CakePHP Overview Welcome to the Cookbook.org/wiki/Open_source 4 http://en. using CakePHP means your application’s core is well tested and is being constantly improved. the manual for the CakePHP web application framework that makes developing a piece of cake! This manual assumes that you have a general understanding of PHP and a basic understanding of objectoriented programming (OOP). check out a copy of CakePHP and get started with the logic of your application. CakePHP has an active developer team7 and community. CakePHP takes the monotony out of web development. rapid development4 framework5 for PHP6 .wikipedia. It’s a foundational structure for programmers to create web applications. and XML – and this manual does not attempt to explain those technologies. JavaScript.cakephp.org/wiki/Application_framework 6 http://www.org/wiki/MIT_License 3 http://en.php. Instead of reinventing the wheel every time you begin a new project.org/wiki/Rapid_application_development 5 http://en. Our primary goal is to enable you to work in a structured and rapid manner–without loss of flexibility. What is CakePHP? Why use it? CakePHP1 is a free2 . Different functionality within the framework makes use of different technologies – such as SQL.com/cakephp?tab=members 2 45 .net/ 7 https://github. Here’s a quick list of features you’ll enjoy when using CakePHP: • Active.wikipedia. only how they are used in context. In addition to keeping you from wheel-reinventing.org/ http://en. bringing great value to the project.wikipedia. open-source3 .

org/wiki/Data_validation 13 http://en.org/wiki/Scaffold_(programming) 11 http://en. CakePHP Overview .org/wiki/Web_cache 16 http://httpd.wikipedia.8 and greater • Integrated CRUD9 for database interaction • Application scaffolding10 • Code generation • MVC11 architecture • Request dispatcher with clean.wikipedia. session. and request handling Components • Flexible ACL14 • Data sanitization • Flexible caching15 • Localization • Works from any web site directory. HTML forms and more • Email. custom URLs and routes • Built-in validation12 • Fast and flexible templating13 (PHP syntax.org/wiki/Model-view-controller 12 http://en.2. Programming using MVC separates your application into three main parts: The Model layer The Model layer represents the part of your application that implements the business logic.wikipedia. JavaScript.org/wiki/MIT_License http://en. This includes processing.wikipedia.wikipedia. with helpers) • View helpers for AJAX.x • Flexible licensing8 • Compatible with versions PHP 5.apache.org/wiki/Web_template_system 14 http://en.wikipedia._update_and_delete 10 http://en.CakePHP Cookbook Documentation. It is responsible for retrieving data and converting it into meaningful concepts for your application.org/ 17 http://en. with little to no Apache16 configuration involved Understanding Model-View-Controller CakePHP follows the MVC17 software design pattern.org/wiki/Model-view-controller 9 46 Chapter 3.wikipedia.wikipedia.org/wiki/Create. security. validating. cookie. associating or other tasks related to handling data. 8 http://en.wikipedia. Release 2.org/wiki/Access_control_list 15 http://en._read.

or “Photo”. it is responsible for using the information it has available to produce any presentational interface your application might need. Release 2. Model objects can be looked at as the first layer of interaction with any database you might be using for your application.CakePHP Cookbook Documentation. delegates data fetching or processing to the model. Being separated from the Model objects. It is responsible for rendering a response with the aid of both the Model and the View layer. selects the type of presentational data that the clients are accepting. as the Model layer returns a set of data. “Comment”. But in general they stand for the major concepts around which you implement your application. saving friends’ associations. storing and retrieving user photos. and finally delegates the rendering process to the View layer. In the case of a social network. It can be used to deliver a wide variety of formats depending on your needs. A controller can be seen as a manager that ensures that all resources needed for completing a task are delegated to the correct workers. The View layer is not only limited to HTML or text representation of the data. For example. The View layer The View renders a presentation of modeled data.x At a first glance. checks their validity according to authentication or authorization rules. the Model layer would take care of tasks such as saving the user data. such as videos. “User”. etc. the view would use it to render a HTML page containing it. music. or a XML formatted result for others to consume. It waits for petitions from clients. Understanding Model-View-Controller 47 . documents and any other format you can think of. The model objects can be thought as “Friend”. The Controller layer The Controller layer handles requests from users. finding suggestions for new friends.

New features are easily added. Separation also allows developers to make changes in one part of the application without affecting the others. including the ability to rapidly prototype18 . try the blog tutorial now 18 48 http://en. and controllers makes your application very light on its feet. We’ll add some details later on which are specific to CakePHP. it will communicate with the Model layer to process any datafetching or -saving operation that might be needed. Once the request arrives at the controller. Finally. you won’t want to do it any other way. and new faces on old features are a snap. Benefits Why use MVC? Because it is a tried and true software design pattern that turns an application into a maintainable. To get started on your first CakePHP application. Crafting application tasks into separate models. it is immediately rendered to the user.x CakePHP request cycle Figure: 1: A typical MVC Request in CakePHP The typical CakePHP request cycle starts with a user requesting a page or resource in your application. so keep this in mind as we proceed. After this communication is over. modular. rapidly developed package. Release 2. it takes some time getting used to. the controller will proceed to delegate to the correct view object the task of generating output resulting from the data provided by the model. but we’re confident that once you’ve built your first application using CakePHP. CakePHP Overview .wikipedia.org/wiki/Software_prototyping Chapter 3.CakePHP Cookbook Documentation. The modular and separate design also allows developers and designers to work simultaneously. This request is first processed by a dispatcher which will select the correct controller object to handle it. Almost every request to your application will follow this basic pattern. views. when this output is generated. If you’ve never built an application this way.

The Test Cases If you ever feel the information provided in the API is not sufficient. As with many other open source projects. and downloads.org This manual should probably be the first place you go to get answers. It features links to oft-used developer tools. It’s a straight forward code reference. so bring your propeller hat.org The Official CakePHP website is always a great place to visit. log on and share your knowledge with the community and gain instant fame and fortune.net: Where to Get Help 49 . screencasts. and code examples. we get new folks regularly. The API http://api.org/ Straight to the point and straight from the core developers.CakePHP Cookbook Documentation. The Bakery http://bakery.cakephp.x Where to Get Help The Official CakePHP website http://www.cakephp. donation opportunities.freenode. but will remain longer – and you’ll also be lightening our support load. The Cookbook http://book.cakephp. Try your best to answer your questions on your own first. Check it out for tutorials. Answers may come slower. check out the code of the test cases provided with CakePHP. Release 2. case studies.org The CakePHP Bakery is a clearing house for all things regarding CakePHP. the CakePHP API (Application Programming Interface) is the most comprehensive documentation around for all the nitty gritty details of the internal workings of the framework. They can serve as practical examples for function and data member usage for a class. Once you’re acquainted with CakePHP. lib/Cake/Test/Case The IRC channel IRC Channels on irc. Both the manual and the API have an online component.cakephp.

especially during the daylight hours for North and South America users.com/group/cake-php 21 http://stackoverflow.com/21 Tag your questions with cakephp and the specific version you are using to enable existing users of stackoverflow to find your questions.google. solving problems. Official CakePHP discussion group CakePHP Google Group20 CakePHP also has its official discusson group on Google Groups. There are thousands of people discussing CakePHP projects. Where to get Help in your Language French • French CakePHP Community22 19 https://github.x • #cakephp – General Discussion • #cakephp-docs – Documentation • #cakephp-bakery – Bakery If you’re stumped. Release 2.org 20 50 Chapter 3.com/questions/tagged/cakephp/ 22 http://cakephp-fr. frequently asked questions. Stackoverflow http://stackoverflow. Join other CakePHP users and start discussing.CakePHP Cookbook Documentation. CakePHP Overview . helping each other. give us a holler in the CakePHP IRC channel. Someone from the development team19 is usually there.com/cakephp?tab=members http://groups. It can be a great resource for finding archived answers. want to find users in your area. building projects and sharing ideas. and getting answers to immediate problems. whether you need some help. or would like to donate your brand new sports car. We’d love to hear from you.

php and it should contain methods that are shared between all of your application’s controllers. You want to keep your controllers thin. a controller is named after the primary model it handles. After routing has been applied and the correct controller has been found. and your models fat. a controller is used to manage the logic around a single model. Commonly.CHAPTER 4 Controllers Controllers are the ‘C’ in MVC. you might have a RecipesController managing your recipes and an IngredientsController managing your ingredients. Controllers provide a number of methods that handle requests.php as follows: class AppController extends Controller { } Controller attributes and methods created in your AppController will be available to all of your application’s controllers. This will help you more easily reuse your code and makes your code easier to test. each public method in a controller is an action. Controllers can be thought of as middle man between the Model and View. which in turn extends the core Controller class. Components (which you’ll learn about later) are best used for code that is used in many (but not necessarily all) controllers. Your application’s controllers extend the AppController class. By default. it’s also possible to have controllers work with more than one model. These are called actions. In CakePHP. and the right response or view is rendered. Your controller should handle interpreting the request data. and is accessible from a URL. if you were building a site for an online bakery. For example. the AppController class is the parent class to all of your application’s controllers. However. Usually responses are in the form of a rendered view. but there are other ways to create responses as well. making sure the correct models are called. your controller’s action is called. The AppController class can be defined in /app/Controller/AppController. AppController is defined in /app/Controller/AppController. An action is responsible for interpreting the request and creating the response. 51 . AppController itself extends the Controller class included in the CakePHP core library. The App Controller As stated in the introduction.

Also remember to call AppController‘s callbacks within child controller callbacks for best results: public function beforeFilter() { parent::beforeFilter(). Note: CakePHP merges the following variables from the AppController into your application’s controllers: • $components • $helpers • $uses Remember to add the default Html and Form helpers if you define the $helpers property in your AppController.. CakePHP uses conventions to automate this process and remove some boilerplate code you would otherwise need to write. Returning to our online bakery example. The controller would be found in /app/Controller/RecipesController. Controllers . CakePHP puts all of the important request information into the $this->request property. In these cases. The values in the child class will always override those in AppController. CakePHP’s Router and Dispatcher classes use Routes Configuration to find and create the correct controller. $recipeId) { //action logic goes here. CakePHP does a bit of extra work when it comes to special controller attributes. AppController value arrays are merged with child controller class arrays. share(). CakePHP renders a view with an inflected version of the action name. and search() actions. } Request parameters When a request is made to a CakePHP application. By convention. See the section on CakeRequest for more information on the CakePHP request object.x While normal object-oriented inheritance rules apply.CakePHP Cookbook Documentation. our RecipesController might contain the view(). The request data is encapsulated in a request object. 52 Chapter 4.php class RecipesController extends AppController { public function view($id) { //action logic goes here. The components and helpers used by a controller are treated specially. } public function share($customerId. Controller actions Controller actions are responsible for converting the request parameters into a response for the browser/user making the request.. Release 2.php and contain: # /app/Controller/RecipesController.

The conventional view file name is the lowercased and underscored version of the action name.ctp. Returning array data to a non-requestAction request will cause errors and should be avoided. Instead. it will be used as the response body. you don’t need to create and render the view manually. Controller actions generally use set() to create a context that View uses to render the view. both of the following techniques will bypass the default view rendering behavior. } } The above controller action is an example of how a method can be used with requestAction() and normal requests. } } The view files for these actions would be app/View/Recipes/view.CakePHP Cookbook Documentation. See the section on requestAction() for more tips on using requestAction() In order for you to use a controller effectively in your own application.ctp. If for some reason you’d like to skip the default behavior. Because of the conventions that CakePHP uses. Request Life-cycle callbacks class Controller CakePHP controllers come fitted with callbacks you can use to insert logic around the request life-cycle: Controller::beforeFilter() This function is executed before every action in the controller.. or an object that can be converted to a string from your controller action. CakePHP will handle rendering and delivering the View. } $this->set('popular'. Release 2. $popular). It’s a handy place to check for an active Request Life-cycle callbacks 53 . When you use controller methods with requestAction(). you will often want to return data that isn’t a string. if (!empty($this->request->params['requested'])) { return $popular. • If you return a string. once a controller action has completed.x } public function search($query) { //action logic goes here.ctp. • You can return a CakeResponse object with the completely created response. If you have controller methods that are used for normal web requests + requestAction. and app/View/Recipes/search. app/View/Recipes/share. you should check the request type before returning: class RecipesController extends AppController { public function popular() { $popular = $this->Recipe->popular(). we’ll cover some of the core attributes and methods provided by CakePHP’s controllers.

First.cakephp. and after rendering is complete.org/2.html Chapter 4. This can often be a quick way to assign a set of information to the view: $data = array( 'color' => 'pink'. Controller::set(string $var. Controller::beforeRender() Called after controller action logic. Controller::afterFilter() Called after every controller action. Controller Methods For a complete list of controller methods and their descriptions visit the CakePHP API1 .x session or inspect user permissions. mixed $value) The set() method is the main way to send data from your controller to your view. they are able to pass data to the views. 'base_price' => 23. and $base_price // available to the view: 1 54 http://api. but may be needed if you are calling render() manually before the end of a given action.8/class-Controller. In addition to controller life-cycle callbacks. You can also decide which view class to use. Controllers . but before the view is rendered. Components also provide a similar set of callbacks. 'type' => 'sugar'. // Then. This is the last controller method to run. This callback is not used often. and scaffolded actions. in the view. $type. using set(). and which view file should be rendered from the controller. you can utilize the data: ?> You have selected <?php echo $color. the variable can be accessed in your view: // First you pass data from the controller: $this->set('color'. ?> icing for the cake. Interacting with Views Controllers interact with views in a number of ways. 'pink').95 ). Release 2. Note: The beforeFilter() method will be called for missing actions. Once you’ve used set().CakePHP Cookbook Documentation. The set() method also takes an associative array as its first parameter. // make $color.

Use set() to set the title: $this->set('title_for_layout'. the view file in /app/View/Recipes/search.CakePHP Cookbook Documentation. If $view starts with ‘/’.ctp $this->render(). } Although CakePHP will automatically call it after every action’s logic (unless you’ve set $this->autoRender to false). use view blocks instead. Controller::render(string $view..ctp instead of You can also render views inside plugins using the following syntax: $this->render(’PluginName. } // .x $this->set($data). The $layout parameter allows you to specify the layout with which the view is rendered.. You can do this by calling render() directly. it is assumed to be a view or element file relative to the /app/View folder. places the view inside its $layout.PluginController/custom_file’). The attribute $pageTitle no longer exists. 'This is the page title'). very useful in AJAX calls. you can use it to specify an alternate view file by specifying a view name in the controller using $view. Once you have called render(). Release 2. CakePHP will not try to re-render the view: class PostsController extends AppController { public function my_action() { $this->render('custom_file').. For example: Controller Methods 55 . This allows direct rendering of elements. } } This would render app/View/Posts/custom_file. public function search() { // Render the view in /View/Recipes/search. If the search() action of the RecipesController is requested.. The default view file used by render is determined by convention.ctp will be rendered: class RecipesController extends AppController { // . Rendering a specific view In your controller. string $layout) The render() method is automatically called at the end of each requested controller action. and serves it back to the end user.ctp $this->render('/Elements/ajaxreturn'). This method performs all the view logic (using the data you’ve submitted using the set() method). // Render the element in /View/Elements/ajaxreturn.ctp app/View/Posts/my_action.5 the variable $title_for_layout is deprecated. As of 2. you may want to render a different view than the conventional one.

integer $status. If you want to redirect to a URL like: http://www. you might wish to redirect them to a receipt screen. boolean $exit) The flow control method you’ll use most often is redirect().UserDetails/custom_file'). $this->redirect('http://www.ctp Flow Control Controller::redirect(mixed $url. 56 Chapter 4. 'action' => 'thanks') ). Controllers .com'). If you need to redirect to the referer page you can use: $this->redirect($this->referer()).example. } You can also use a relative or absolute URL as the $url argument: $this->redirect('/orders/thanks'). 'action' => 'confirm'. When a user has successfully placed an order. 'action' => 'confirm') ).CakePHP Cookbook Documentation.x class PostsController extends AppController { public function my_action() { $this->render('Users. } return $this->redirect( array('controller' => 'orders'. You can also pass data to the action: $this->redirect(array('action' => 'edit'. You may want to use 301 (moved permanently) or 303 (see other). $id)). } } This would render app/Plugin/Users/View/UserDetails/custom_file. The method also supports name-based parameters. The method will issue an exit() after the redirect unless you set the third parameter to false.com/orders/confirm/product:pizza/quantity:5 you can use: $this->redirect(array( 'controller' => 'orders'. Release 2. depending on the nature of the redirect. public function place_order() { // Logic for finalizing order goes here if ($success) { return $this->redirect( array('controller' => 'orders'. The second parameter of redirect() allows you to define an HTTP status code to accompany the redirect. This method takes its first parameter in the form of a CakePHP-relative URL.example.

the flash() method is used to direct a user to a new page after an operation. The first parameter should hold the message to be displayed. and the second parameter is a CakePHPrelative URL. 'action' => 'confirm'. string $layout) Like redirect(). etc. For in-page flash messages. CakePHP also supports callbacks related to scaffolding. Controller::afterScaffoldSave($method) $method name of method called either edit or update. '?' => array( 'product' => 'pizza'. Controller Methods 57 .com/orders/confirm?product=pizza&quantity=5#top Controller::flash(string $message. edit. CakePHP will display the $message for $pause seconds before forwarding the user on. Callbacks In addition to the Request Life-cycle callbacks. be sure to check out SessionComponent::setFlash() method. Controller::scaffoldError($method) $method name of method called example index. An example using query strings and hash would look like: $this->redirect(array( 'controller' => 'orders'. If there’s a particular template you’d like your flashed message to use.CakePHP Cookbook Documentation.example. 'quantity' => 5 ). you may specify the name of that layout in the $layout parameter. etc. integer $pause. edit. '#' => 'top') ). string|array $url. 'quantity' => 5) ). The flash() method is different in that it shows a message before passing the user on to another URL. Release 2. Controller::afterScaffoldSaveError($method) $method name of method called either edit or update. Controller::beforeScaffold($method) $method name of method called example index.x 'product' => 'pizza'. The generated URL would be: http://www.

. boolean $local = false) Returns the referring URL for the current request. but this method is handy to have when accessing controllers from a different perspective. an administrative user may want to be able to search orders in order to know which items need to be shipped. Controller::disableCache() Used to tell the user’s browser not to cache the results of the current request.‘/’. restricts referring URLs to local server. instead of doing this: class UserController extends AppController { public function delete($id) { // delete code goes here.. The headers sent to this effect are: Expires: Mon.x Other Useful Methods Controller::constructClasses() This method loads the models required by the controller.. must-revalidate Cache-Control: post-check=0. string $bool.CakePHP Cookbook Documentation. if ($this->referer() != '/') { return $this->redirect($this->referer()). Parameter $local if set to true. Controller::referer(mixed $default = null. This function offers a quick shortcut on building search logic. mixed $op. Parameter $default can be used to supply a default URL to use if HTTP_REFERER cannot be read from headers. pre-check=0 Pragma: no-cache Controller::postConditions(array $data. If you need CakePHP in a command-line script or some other outside use. and then. } } If $default is not set. You can use CakePHP’s FormHelper and HtmlHelper to create a quick form 58 Chapter 4. This is different than view caching. } } you can do this: class UserController extends AppController { public function delete($id) { // delete code goes here. Release 2. and then. no-cache. So. 26 Jul 1997 05:00:00 GMT Last-Modified: [current datetime] GMT Cache-Control: no-store. boolean $exclusive) Use this method to turn a set of POSTed model data (from HtmlHelper-compatible inputs) into a set of find conditions for a model. return $this->redirect( $this->referer(array('action' => 'index')) ). Controllers . For example.. covered in a later chapter. the function defaults to the root of your domain . constructClasses() may come in handy. This loading process is done by CakePHP normally. } return $this->redirect(array('action' => 'index')).

Note: You can use requestAction() to retrieve a fully rendered view by passing ‘return’ in the options: requestAction($url. fields not included in $op will not be included in the returned conditions. ‘OR’ and ‘XOR’ are all valid values. See the pagination section for more details on how to use paginate. $this->set('orders'. compact('conditions')). supply them using the second parameter: /* Contents of $this->request->data array( 'Order' => array( 'num_items' => '4'. In this case. and the $op parameter is an array.CakePHP Cookbook Documentation. 'referrer' => 'Ye Olde' ) ) */ // Let's get orders that have at least 4 items and contain 'Ye Olde' $conditions = $this->postConditions( $this->request->data.destination’ => ’Old Towne Bakery’). $orders). array $options) This function calls a controller’s action from any location and returns data from the action. If you want to use a different SQL operator between terms. The $url passed is a CakePHP-relative URL (/controllername/actionname/params). Strings like ‘AND’. model find conditions and more. The third parameter allows you to tell CakePHP what SQL boolean operator to use between the find conditions. compact('conditions')). $orders = $this->Order->find('all'. array(’return’)). Controller::paginate() This method is used for paginating results fetched by your models. 'referrer' => 'LIKE' ) ). $orders = $this->Order->find('all'. Controller::requestAction(string $url. } If $this->request->data[’Order’][’destination’] equals “Old Towne Bakery”. To pass extra data to the receiving controller action add to the $options array. array(’Order. You can specify page sizes. Then a controller action can use the data posted from that form to craft find conditions: public function index() { $conditions = $this->postConditions($this->request->data). if the last parameter is set to true..x based on the Order model. Release 2. array( 'num_items' => '>='. Controller Methods 59 . Finally. It is important to note that making a requestAction() using return from a controller method can cause script and CSS tags to not work correctly. postConditions converts that condition to an array compatible for use in a Model->find() method.

and returned. array('order' => 'Comment. 60 Chapter 4. array('return') ). First we need to create a controller function that will return the data: // Controller/CommentsController. The requestAction() call will not be made while the cached element view file exists and is valid.x Warning: If used without caching requestAction() can lead to poor performance. } return $this->Comment->find( 'all'.created DESC'. foreach ($comments as $comment) { echo $comment['Comment']['title']. Release 2. whenever the element is rendered. Let’s use the example of putting a “latest comments” element in the layout.php class CommentsController extends AppController { public function latest() { if (empty($this->request->params['requested'])) { throw new ForbiddenException(). requestAction() now takes array based cake style URLs: echo $this->requestAction( array('controller' => 'articles'. If we now create a simple element to call that function: // View/Elements/latest_comments. However in accordance with the warning above it’s best to make use of element caching to prevent needless processing. Controllers .CakePHP Cookbook Documentation. It is rarely appropriate to use in a controller or model. By modifying the call to element to look like this: echo $this->element('latest_comments'. the data will be processed. 'limit' => 10) ). Written in this way.ctp $comments = $this->requestAction('/comments/latest'). } } You should always include checks to make sure your requestAction() methods are actually originating from requestAction(). a request will be made to the controller to get the data. requestAction() is best used in conjunction with (cached) elements – as a way to fetch data for an element before rendering. array('cache' => true)). which is generally undesirable. array(). Failing to do so will allow requestAction() methods to be directly accessible from a URL. } We can then place that element anywhere to get the output using: echo $this->element('latest_comments'). 'action' => 'featured'). In addition.

'action' => 'view'). Controller Attributes For a complete list of controller attributes and their descriptions visit the CakePHP API2 .8/class-Controller. requestAction() treats them differently. mixed $id) The loadModel() function comes handy when you need to use a model which is not the controller’s default model or its associated model: $this->loadModel('Article'). echo $this->requestAction('/articles/view/5'). $this->loadModel('User'.cakephp. Additional members in the $option array will also be made available in the requested action’s Controller::params array: echo $this->requestAction('/articles/featured/limit:3'). The url based arrays are the same as the ones that HtmlHelper::link() uses with one difference . array('named' => array('limit' => 3)) ). Release 2. When using an array url in conjunction with requestAction() you must specify all parameters that you will need in the requested action. you must put them in a second array and wrap them with the correct key. 2 http://api. This is because requestAction() merges the named args array (requestAction’s 2nd parameter) with the Controller::params member array and does not explicitly place the named args array into the key ‘named’. array('pass' => array(5)) ). $recentArticles = $this->Article->find( 'all'.x This allows the requestAction() call to bypass the usage of Router::url() which can increase performance. 'action' => 'featured'). This includes parameters like $this->request->data. named and pass parameters must be done in the second array as seen above. 'order' => 'Article. In addition to passing all required parameters.html Controller Attributes 61 . $user = $this->User->read().CakePHP Cookbook Documentation.created DESC') ). Controller::loadModel(string $modelClass. echo $this->requestAction( array('controller' => 'articles'. 2). Note: Unlike other places where array URLs are analogous to string URLs. As an array in the requestAction() would then be: echo $this->requestAction( array('controller' => 'articles'.if you are using named or passed parameters. array('limit' => 5.org/2.

CakePHP Cookbook Documentation. when allowing a controller to access additional models through the $uses variable. property Controller::$uses Controllers have access to their primary model available by default. public $components = array('RequestHandler'). and models you’ll be using in conjunction with the current controller. Changed in version 2. Usually this is just the plural form of the primary model the controller uses. $components. But if you choose to define your own $helpers array in AppController. To learn more about these classes. and our ProductsController also features the Product model at $this->Product. for example) and those given by $helpers to the view as an object reference variable ($this->{$helpername}). public $helpers = array('Js'). If you do not wish to use a Model in your controller. make sure to include HtmlHelper and FormHelper if you want them still available by default in your Controllers. You can also use false to not load any models at all. but saves CakePHP from inflecting it: // $name controller attribute usage example class RecipesController extends AppController { public $name = 'Recipes'. 'User'). Controllers . it also handles false differently. FormHelper. property Controller::$helpers The HtmlHelper. However. } 62 Chapter 4. so you may not need to configure your controller at all. the name of the current controller’s model must also be included. Even those defined in the AppController. as is the SessionComponent. This is illustrated in the example below. Release 2. Our RecipesController will have the Recipe model class available at $this->Recipe. and SessionHelper are available by default. be sure to check out their respective sections later in this manual. This will allow you to use a controller without a need for a corresponding Model file.1: $uses now has a new default value. This property can be omitted. Note: Each controller has some of these classes available by default. set public $uses = array(). the models defined in the AppController will still be loaded. Using these attributes make MVC classes given by $components and $uses available to the controller as class variables ($this->ModelName. Let’s look at how to tell a CakePHP Controller that you plan to use additional MVC classes: class RecipesController extends AppController { public $uses = array('Recipe'.x property Controller::$name The $name attribute should be set to the name of the controller. } $components. $helpers and $uses The next most often used controller attributes tell CakePHP what $helpers. However.

Using it loads and configures the PaginatorComponent. Release 2. It centralizes a number of features for interrogating and interacting with request data. CakeRequest and CakeResponse are used for this purpose. You can read more about full page caching in the CacheHelper documentation. there are other controller attributes that merit their own sections in the manual. and the related methods were spread across RequestHandlerComponent. Dispatcher and Controller. property Controller::$cacheAction The cacheAction attribute is used to define the duration and other information about full page caching. On each request. Router. } More on controllers Request and Response objects New in CakePHP 2. CakeRequest CakeRequest is the default request object used in CakePHP. one CakeRequest is created and then passed 3 http://api. or anything that is declared in your AppController. these objects were represented through arrays. See Configuring Components for more information.0.0 are request and response objects.x Each of these variables are merged with their inherited values.cakephp. As with $helpers you can pass settings into $components. It is recommended that you update your code to use normal component settings: class ArticlesController extends AppController { public $components = array( 'Paginator' => array( 'Article' => array( 'conditions' => array('published' => 1) ) ) ).org More on controllers 63 . therefore it is not necessary (for example) to redeclare the FormHelper. property Controller::$components The components array allows you to set which Components a controller will use. property Controller::$paginate The paginate attribute is a deprecated compatibility property. Like $helpers and $uses components in your controllers are merged with those in AppController. In previous versions.CakePHP Cookbook Documentation. Other Attributes While you can check out the details for all controller attributes in the API3 . There was no authoritative object on what information the request contained. For 2.

$this->request['pass']. $this->request->params['controller']. 64 Chapter 4. you also often need access to Passed Arguments and Named Parameters. You can also access it in Components by using the controller reference. $this->request['controller']. and the subdomain/domain information about the application the server is running on. CakeRequest is assigned to $this->request. // named parameters $this->request->named. • prefix The prefix for the current action. $this->request->params['named']. $this->request['named']. See Prefix Routing for more information. There are several important/useful parameters that CakePHP uses internally. All of these will provide you access to the passed arguments and named parameters. Release 2. These are also all found in the request parameters: • plugin The plugin handling the request. All Route Elements are accessed through this interface. the second uses array indexes. These are both available on the request object as well: // Passed arguments $this->request->pass. In addition to Route Elements. Will be null when there is no plugin. All of the above will access the same value. POST. Multiple ways of accessing the parameters have been provided to ease migration for existing applications. • bare Present when the request came from requestAction() and included the bare option.x by reference to the various layers of an application that use request data. Bare requests do not have layouts rendered. By default. Accessing request parameters CakeRequest exposes several interfaces for accessing request parameters.CakePHP Cookbook Documentation. • Provide environment introspection pertaining to the request. Controllers . $this->request->params['pass']. and is available in Controllers. Things like the headers sent. Some of the duties CakeRequest performs include: • Process the GET. Views and Helpers. and FILES arrays into the data structures you are familiar with. • Provide access to request parameters both as array indexes and object properties. The first uses object properties. • controller The controller handling the current request. • requested Present and set to true when the action came from requestAction(). the client’s IP address. • action The action handling the current request. and the third uses $this->request->params: $this->request->controller.

does.not. Any keys that do not exist will return null: $foo = $this->request->data('Value. Any keys that do not exist will return null: $foo = $this->request->query('value_that_does_not_exist'). // You can also access it via an array // Note: BC accessor. You can either directly access the $query property. More on controllers 65 .2.2. By providing a decoding function.x Accessing Querystring parameters Querystring parameters can be read using CakeRequest::$query: // URL is /posts/index?page=1&sort=title $this->request->query['page']. you can receive the content in a deserialized format: // Get JSON encoded data submitted to a PUT/POST action $data = $this->request->input('json_decode'). For example: // An input with a name attribute equal to 'data[MyModel][title]' // is accessible at $this->request->data['MyModel']['title']. If you are accepting JSON or XML data. Any form data that contains a data prefix will have that data prefix removed.exist'). As of 2. You can either directly access the $data property.that. any application/x-www-form-urlencoded request body data will automatically be parsed and set to $this->data for PUT and DELETE requests. // $foo === null Accessing POST data All POST data can be accessed using CakeRequest::$data. When building REST services. Release 2. will be deprecated in future versions $this->request['url']['page'].CakePHP Cookbook Documentation. you often accept request data on PUT and DELETE requests. see below for how you can access those request bodies. You can read input data in any format using CakeRequest::input(). Accessing XML or JSON data Applications employing REST often exchange data in non-URL-encoded post bodies. or you can use CakeRequest::query() to read the URL query array in an error-free manner. or you can use CakeRequest::data() to read the data array in an error-free manner. // $foo == null Accessing PUT or POST data New in version 2.

Pattern value comparison allows you to compare a value fetched from env() to a regular expression. • Callback detectors .Compares a value fetched from env() for equality with the provided value. These methods have been moved to CakeRequest. Accessing path information CakeRequest also provides useful information about the paths in your application.Option based comparisons use a list of options to create a regular expression. For the time being. $this->request->isPost(). the methods are still available on RequestHandlerComponent.Callback detectors allow you to provide a ‘callback’ type to handle the check. CakeRequest::input() supports passing in additional parameters as well: // Get Xml encoded data submitted to a PUT/POST action $data = $this->request->input('Xml::build'. array('env' => 'HTTP_USER_AGENT'. The callback will receive the request object as its only parameter. Some examples would be: // Add an environment detector. • Pattern value comparison . If you want XML converted into a DOMDocument object. Subsequent calls to add an already defined options detector will merge the options.0. CakeRequest::$base and CakeRequest::$webroot are useful for generating URLs. array('env' => 'REQUEST_METHOD'. 'pattern' => '/iPhone/i') 66 Chapter 4. There are four different types of detectors that you can create: • Environment value comparison .CakePHP Cookbook Documentation. // deprecated Both method calls will return the same value. array('return' => 'domdocument')). You can also easily extend the request detectors that are available by using CakeRequest::addDetector() to create new kinds of detectors. // Add a pattern value detector. $this->request->addDetector( 'iphone'. 'value' => 'POST') ). and offer a new interface alongside a more backwards-compatible usage: $this->request->is('post').x Some deserializing methods require additional parameters when called. but are deprecated and will be removed in 3. such as the ‘as array’ parameter on json_decode.0. Release 2. Controllers . and determining whether or not your application is in a subdirectory. Inspecting the request Detecting various request conditions used to require using RequestHandlerComponent. • Option based comparison . $this->request->addDetector( 'post'.

0. // Add a callback detector. 'options' => array('192. • is(’ajax’) Check to see whether the current request came with X-Requested-With = XMLHttpRequest. $this->request->addDetector('internalIp'. There are several built-in detectors that you can use: • is(’get’) Check to see whether the current request is a GET. For 2.100') )). $this->request->addDetector( 'awesome'. array('callback' => function ($request) { return isset($request->awesome). on top of the utility that CakeRequest affords.168. This separation of utility and sugar between the two classes lets you more easily choose what you want.x ).0.168.101'. CakeRequest also includes methods like CakeRequest::domain(). RequestHandlerComponent provides a layer of sugar.0. CakeRequest::subdomains() and CakeRequest::host() to help applications with subdomains. '192. • is(’ssl’) Check to see whether the request is via SSL • is(’flash’) Check to see whether the request has a User-Agent of Flash • is(’mobile’) Check to see whether the request came from a common list of mobile agents. • is(’put’) Check to see whether the current request is a PUT. such as switching layout and views based on content. • is(’options’) Check to see whether the current request is OPTIONS. More on controllers 67 . some rethinking was required to figure out how it still fits into the picture.CakePHP Cookbook Documentation. Can either be an anonymous function // or a regular callable. Release 2. array( 'env' => 'CLIENT_IP'. • is(’post’) Check to see whether the current request is a POST. CakeRequest and RequestHandlerComponent Since many of the features CakeRequest offers used to be the realm of RequestHandlerComponent. }) ). • is(’head’) Check to see whether the current request is HEAD. // Add an option detector. • is(’delete’) Check to see whether the current request is a DELETE.

• $this->request->base contains the base path.3. If not matched. will throw MethodNotAllowedException. you can also find out other information from various properties and methods. CakeRequest API class CakeRequest CakeRequest encapsulates request parameter handling and introspection. CakeRequest::allowMethod($methods) Set allowed HTTP methods. CakeRequest::subdomains($tldLength = 1) Returns the subdomains your application is running on as an array. For example: $this->request->header('User-Agent'). CakeRequest::clientIp($safe = true) Returns the current visitor’s IP address. Release 2. • $this->request->query contains the query string parameters.5.5: Use CakeRequest::allowMethod() instead. If not matched will throw MethodNotAllowedException.x Interacting with other aspects of the request You can use CakeRequest to introspect a variety of things about the request. 68 Chapter 4. CakeRequest::method() Returns the HTTP method the request was made with. Controllers . CakeRequest::onlyAllow($methods) Set allowed HTTP methods. • $this->request->here contains the full address to the current request. would return the user agent used for the request. CakeRequest::domain($tldLength = 1) Returns the domain name your application is running on. CakeRequest::host() Returns the host your application is on. Deprecated since version 2. CakeRequest::referer($local = false) Returns the referring address for the request. The 405 response will include the required Allow header with the passed methods New in version 2. • $this->request->webroot contains the webroot directory. Beyond the detectors. CakeRequest::header($name) Allows you to access any of the HTTP_* headers that were used for the request. The 405 response will include the required Allow header with the passed methods New in version 2.CakePHP Cookbook Documentation.

See Inspecting the request for more information.title'. $this->request->data('Post. CakeRequest::addDetector($name. and optionally pass it through a decoding function. Release 2. $options ]) Retrieve the input data for a request. Allows request data to be read and modified. Additional parameters for the decoding function can be passed as arguments to input(): $this->request->input('json_decode').1. static CakeRequest::acceptLanguage($language = null) Get all the languages accepted by the client. or check whether it accepts a particular type of content. // You can also read out data. so you can prepopulate some form fields. CakeRequest::query($name) Provides dot notation access to URL query data: // URL is /posts/index?page=1&sort=title $value = $this->request->query('page'). $value = $this->request->data('Post.3.x CakeRequest::input($callback[. Check for a single type: $this->request->accepts('application/json'). Get all types: $this->request->accepts().author'. Useful when interacting with XML or JSON request body content. $options) Add a detector to be used with CakeRequest::is(). CakeRequest::is($type) Check whether or not a Request matches a certain criterion. CakeRequest::accepts($type = null) Find out which content types the client accepts. Check whether a specific language is accepted: More on controllers 69 . or check whether a specific language is accepted. Calls can be chained together as well: // Modify some request data.title'). New in version 2. 'New post') ->data('Comment. Uses the built-in detection rules as well as any additional rules defined with CakeRequest::addDetector().CakePHP Cookbook Documentation. CakeRequest::data($name) Provides dot notation access to request data. Get the list of accepted languages: CakeRequest::acceptLanguage(). 'Mark').

• Sending the response body. Controllers . The old methods are deprecated in favour of using CakeResponse. This will make all the controllers in your application use CustomResponse instead of CakeResponse. If you need to override it with your own application-specific class. Like CakeRequest. as it can be mocked/stubbed allowing you to inspect headers that will be sent. CakeResponse consolidates a number of methods previously found on Controller. property CakeRequest::$query An array of query string parameters. This removes the need to call isset() or empty() before using param values.x CakeRequest::acceptLanguage('es-es'). property CakeRequest::$data An array of POST data. property CakeRequest::$base The base path to the application. property CakeRequest::$here Returns the current request uri. You can use CakeRequest::data() to read this property in a way that suppresses notice errors. property CakeRequest::$webroot The current webroot. New in version 2. Release 2. CakeResponse is a flexible and transparent class.CakePHP Cookbook Documentation.php. It encapsulates a number of features and functionality for generating HTTP responses in your application. CakeResponse provides an interface to wrap the common response-related tasks such as: • Sending headers for redirects. Changing the response class CakePHP uses CakeResponse by default. CakeResponse CakeResponse is the default response class in CakePHP. CakeRequest::param($name) Safely read values in $request->params. usually / unless your application is in a subdirectory. you can replace CakeResponse in app/webroot/index. Overriding the response object is handy during testing. as it 70 Chapter 4. RequestHandlerComponent and Dispatcher. property CakeRequest::$params An array of route elements and request parameters. • Sending any header. • Sending content type headers. You can also replace the response instance by setting $this->response in your controllers.4. It also assists in testing.

As of 2. Release 2. CakePHP will send a proper content type header if it’s a known file type listed in CakeResponse::$_mimeTypes. so you can leverage the automatic view switching features of RequestHandlerComponent if you are using it. MediaView is deprecated and you can use CakeResponse::file() to send a file as response: public function sendFile($id) { $file = $this->Attachment->getFile($id). // Return response object to prevent controller from trying to render // a view return $this->response. If you want. Dealing with content types You can control the Content-Type of your application’s responses with CakeResponse::type(). // Set the response Content-Type to vcard.3. Usually. Sending a string as file You can respond with a file that does not exist on the disk. } As shown in the above example. Prior to version 2. you could use MediaView.x allows you to stub out the methods that interact with header(). If your application needs to deal with content types that are not built into CakeResponse. array('download' => true. See the section on CakeResponse and testing for more information.3. 'name' => 'foo') ). Sending files There are times when you want to send files as responses for your requests. $this->response->file($file['path']). $this->response->type('vcf'). you can also force a file to be downloaded instead of displayed in the browser by specifying the options: $this->response->file( $file['path']. You can add new types prior to calling CakeResponse::file() by using the CakeResponse::type() method. you can map them with CakeResponse::type() as well: // Add a vCard type $this->response->type(array('vcf' => 'text/v-card')).CakePHP Cookbook Documentation. you must pass the file path to the method. you’ll want to map additional content types in your controller’s beforeFilter() callback. such as a pdf or an ics generated on the fly from a string: More on controllers 71 .

} Setting headers Setting headers is done with the CakeResponse::header() method. just as regular header calls do. Controllers . You can now use the convenience method CakeResponse::location() to directly set or get the redirect location header. 'http://example. It can be called with a few different parameter configurations: // Set a single header $this->response->header('Location'. $this->response->disableCache(). instead they are buffered until the response is actually sent. $this->response->header(array( 'WWW-Authenticate: Negotiate'.com'). New in version 2. $this->response->body($icsString). //Optionally force file download $this->response->download('filename_for_download. Headers are not sent when CakeResponse::header() is called. } 72 Chapter 4. 'X-Extra' => 'My header' )). Release 2.4. Interacting with browser caching You sometimes need to force browsers not to cache the results of a controller action. $this->response->type('ics'). // Set multiple headers $this->response->header(array( 'Location' => 'http://example. CakeResponse::disableCache() is intended for just that: public function index() { // do something.ics'). 'Content-type: application/pdf' )).com'. // Return response object to prevent controller from trying to render // a view return $this->response.x public function sendIcs() { $icsString = $this->Calendar->generateIcs().CakePHP Cookbook Documentation. Setting the same header() multiple times will result in overwriting the previous values.

Under this caching model. Expires header and the max-age directive are set based on the second parameter. A Cache-Control header can look like this: Cache-Control: private. you are only required to help clients decide if they should use a cached copy of the response by setting a few headers such as modified time and response entity tag. The first is the CakeResponse::sharable() method. Rather than forcing you to code the logic for caching and for invalidating (refreshing) it once the data has changed. Release 2. the control directive must be set as public.. By using CakeResponse::cache(): public function index() { //do something $this->response->cache('-1 minute'. The second parameter of this method is used to specify a max-age for the cache. More on controllers 73 .. You can also tell clients that you want them to cache responses. // set the Cache-Control as public for 3600 seconds $this->response->sharable(true. which indicates whether a response is to be considered sharable across different users or clients. To take advantage of shared caches. hopefully speeding up your visitors’ experience. The Cache Control header New in version 2. Cache-Control’s public directive is set as well. this header contains multiple indicators that can change the way browsers or proxies use the cached content. you can also use many other methods to fine-tune HTTP cache headers to take advantage of browser or reverse proxy caching. which usually are much simpler to use. Apart from using CakeResponse::cache().x Warning: Using disableCache() with downloads from SSL domains while trying to send files to Internet Explorer can result in errors. Fine tuning HTTP cache One of the best and easiest ways of speeding up your application is to use HTTP cache. HTTP uses two models.1. } The above would tell clients to cache the resulting response for 5 days. Used under the expiration model. must-revalidate CakeResponse class helps you set this header with some utility methods that will produce a final valid Cache-Control header. This method actually controls the public or private part of this header. '+5 days'). max-age=3600. Setting a response as private indicates that all or part of it is intended for a single user. which is the number of seconds after which the response is no longer considered fresh: public function view() { .CakePHP Cookbook Documentation. 3600). expiration and validation. CakeResponse::cache() sets the Last-Modified value to the first argument.

$this->response->etag($this->Article->generateHash($articles)).. Cache validation in HTTP is often used when content is constantly changing. and asks the application to only generate the response contents if the cache is no longer fresh. Under this model. The Expiration header New in version 2. } CakeResponse exposes separate methods for setting each of the directives in the Cache-Control header. but it asks the application every time whether the resource has changed. } 74 Chapter 4. The etag() method (called entity tag) is a string that uniquely identifies the requested resource. This is commonly used with static resources such as images and other assets.. To take advantage of this header. Controllers . the client continues to store pages in the cache. Release 2.CakePHP Cookbook Documentation. instead of using it directly. This header can be set using the CakeResponse::expires() method: public function view() { $this->response->expires('+5 days'). } This method also accepts a DateTime instance or any string that can be parsed by the DateTime class. } . in order to determine whether it matches a cached resource. as a checksum does for a file.. // set the Cache-Control as private for 3600 seconds $this->response->sharable(false.1. The Etag header New in version 2. You can set the Expires header to a date and time after which the response is no longer considered fresh. 3600).x } public function my_data() { ..1. you must either call the CakeResponse::checkNotModified() method manually or include the RequestHandlerComponent in your controller: public function index() { $articles = $this->Article->find('all'). if ($this->response->checkNotModified($this->request)) { return $this->response.

you only have to mock a single object. $this->response->vary('Accept-Language').CakePHP Cookbook Documentation. CakeResponse and testing Probably one of the biggest wins from CakeResponse comes from how it makes testing controllers and components easier. you can also set the Last-Modified header to indicate the date and time at which the resource was modified for the last time. since controllers and components delegate to CakeResponse. as you can use mocks to avoid the ‘headers sent’ errors that can occur when trying to set headers in CLI... if ($this->response->checkNotModified($this->request)) { return $this->response.1. } Additionally. $this->response->modified($article['Article']['modified']). you might want to serve different content using the same URL.. } . Release 2. $this->response->vary('Accept-Encoding'.x The Last Modified header New in version 2. Setting this header helps CakePHP tell caching clients whether the response was modified or not based on their cache. Instead of having methods spread across several objects. you must either call the CakeResponse::checkNotModified() method manually or include the RequestHandlerComponent in your controller: public function view() { $article = $this->Article->find('first'). } The Vary header In some cases. you can run tests from the command line more easily. Under the HTTP cache validation model. This is often the case if you have a multilingual page or respond with different HTML depending on the browser. // . To take advantage of this header. 'User-Agent'). $this->controller->response->expects($this->once())->method('header'). Under such circumstances you can use the Vary header: $this->response->vary('User-Agent').. This helps you to get closer to a unit test and makes testing controllers easier: public function testSomething() { $this->controller->response = $this->getMock('CakeResponse'). More on controllers 75 .

Release 2. $time = null) Sets the Cache-Control header to be either public or private and optionally sets a max-age directive of the resource New in version 2. $time = ‘+1 day’) Allows you to set caching headers in the response.CakePHP Cookbook Documentation. $weak = false) Sets the Etag header to uniquely identify a response resource. // Get the current redirect location header $location = $this->response->location(). CakeResponse::sharable($public = null. CakeResponse::modified($time = null) Sets the Last-Modified header to a specific date and time in the correct format. You can either use a known content type alias or the full content type name. CakeResponse::checkNotModified(CakeRequest $request) Compares the cache headers for the request object with the cache header from the response and deter- 76 Chapter 4. CakeResponse::header($header = null.1. CakeResponse::charset($charset = null) Sets the charset that will be used in the response.1. CakeResponse::cache($since.1. New in version 2. CakeResponse::disableCache() Sets the headers to disable client caching for the response. New in version 2. CakeResponse::expires($time = null) Allows the Expires header to be set to a specific date.x CakeResponse API class CakeResponse CakeResponse provides a number of useful methods for interacting with the response you are sending to a client. New in version 2. CakeResponse::location($url = null) Allows you to directly set the redirect location header to be sent with the response: // Set the redirect location $this->response->location('http://example.com').1. $value = null) Allows you to directly set one or more headers to be sent with the response. Controllers . CakeResponse::type($contentType = null) Sets the content type of the response. New in version 2. CakeResponse::etag($tag = null.4.

Early database schemas are subject to change. and sends the 304 Not Modified header. New in version 2. Now. Scaffolding in CakePHP also allows developers to define how objects are related to each other. This has a downside: a web developer hates creating forms that never will see real use.0 Application scaffolding is a technique that allows a developer to define and create a basic application that can create.. just scaffolding. CakeResponse::download($filename) Allows you to send a response as an attachment. scaffolding has been included in CakePHP.1. To reduce the strain on the developer..5: Dynamic scaffolding will be removed and replaced in 3. and to set its filename. More on controllers 77 . delete and edit buttons. CakeResponse::send() Once you are done creating a response. CakePHP’s scaffolding is pretty cool. calling send() will send all the set headers as well as the body.. It’s so cool that you’ll want to use it in production apps. covered in the next section. Scaffolding Deprecated since version 2. New in version 2. Scaffolding is a great way of getting the early parts of developing a web application started. This is done automatically at the end of each request by Dispatcher. CakeResponse::compress() Turns on gzip compression for the request. you’re up and running. is a great next step: it generates all the code that would produce the same result as the most current scaffold. update and delete objects.CakePHP Cookbook Documentation. but please realize that scaffolding is. $options = array()) Allows you to set the Content-Disposition header of a file either to display or to download. If so. Scaffolding analyzes your database tables and creates standard lists with add. and to create and break those links. it’s time to pull your scaffolding down in order to write some code.. we think it’s cool too. CakePHP’s bake console. standard forms for editing and standard views for inspecting a single item in the database. All that’s needed to create a scaffold is a model and its controller. CakeResponse::body($content = null) Sets the content body of the response. which is perfectly normal in the early part of the design process.x mines whether it can still be considered fresh. deletes the response content. If you find yourself really wanting to customize your logic and your views. Release 2. Once you set the $scaffold variable in the controller. it’s meant as a temporary way to get up and going.3. It isn’t meant to be completely flexible. retrieve. well. CakeResponse::statusCode($code = null) Allows you to set the status code of the response. It’s a loose structure you throw up real quick during the beginning of a project in order to get started. It allows you to get a basic CRUD application up and going in minutes. CakeResponse::file($path.

com/categories to see your new scaffold. Scaffolding is aware of model’s associations.php public $belongsTo = 'Group'. Once you have enabled admin routing. You will now be able to access admin scaffolded actions: http://example. you will not see any related records in the scaffold views until you manually add the association code to the model.. // In User. you’ll see related User IDs in the Category listings. you can set the $displayField variable in the model. after – populated with IDs or names from the Group table in the New User form: // In Group. If you’d rather see something besides an ID (like the user’s first name). you can use scaffolding to generate an admin interface. This feature makes scaffolding more readable in many instances: class User extends AppModel { public $displayField = 'first_name'. } Creating a simple admin interface with scaffolding If you have enabled admin routing in your app/Config/core. if Group hasMany User and User belongsTo Group. in the controller. Before you do it. array(’admin’)). } Assuming you’ve created even the most basic Category model class file (in app/Model/Category.com/admin/controller/edit 78 Chapter 4. add the $scaffold variable: class CategoriesController extends AppController { public $scaffold. Release 2.CakePHP Cookbook Documentation. if your Category model belongsTo User. your index method will be rendered rather than the scaffolding functionality. assign your admin prefix to the scaffolding variable: public $scaffold = 'admin'. While scaffolding “knows” about model’s associations. Visit http://example. you’re ready to go.php public $hasMany = 'User'.com/admin/controller/view http://example. For example.prefixes’. you have to manually add the following code to your User and Group models. 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 by ID in scaffolding. if you create an index() method in a scaffolded controller. Note: Creating methods in controllers that are scaffolded can cause unwanted results. Controllers . the view displays an empty select input for Group in the New User form. so.x To add scaffolding to your application.com/admin/controller/index http://example.php). For example.php with Configure::write(’Routing.

We still don’t recommend using this technique for production applications.0 the Pages Controller was part of lib/Cake.php. The home page you see after installation is generated using this controller. You can also copy the file from lib/Cake/Console/Templates/skel/Controller/PagesController.1 the Pages Controller is no longer part of the core but ships in the app folder. You are free to modify the Pages Controller to meet your needs.ctp you can access it using the url http://example. you can override individual methods and replace them with your own: public function admin_view($id = null) { // custom code here } Once you have replaced a scaffolded action.php.index.ctp app/View/Posts/scaffold.com/pages/about_us. This is a simple and optional controller for serving up static content. Warning: Do not directly modify ANY file under the lib/Cake folder to avoid issues when updating the core in future. you can create templates.1: With CakePHP 2. If you make the view file app/View/Pages/about_us.ctp Custom scaffolding views for all controllers should be placed like so: app/View/Scaffolds/index.com/admin/controller/add http://example. Customizing Scaffold Views If you’re looking for something a little different in your scaffolded views.ctp app/View/Scaffolds/form. Release 2. Keep in mind that you cannot have both admin and non-admin methods scaffolded at the same time.x http://example.CakePHP Cookbook Documentation. Custom scaffolding views for a specific controller (PostsController in this example) should be placed like so: app/View/Posts/scaffold.com/admin/controller/delete This is an easy way to create a simple backend interface quickly.view.ctp app/View/Scaffolds/view. but such a customization may be useful during prototyping iterations. you will need to create a view file for the action as well.ctp The Pages Controller CakePHP ships with a default controller PagesController. When you “bake” an app using CakePHP’s console utility the Pages Controller is created in your app/Controller/ folder. Changed in version 2. Since 2.form. More on controllers 79 . As with normal scaffolding.ctp app/View/Posts/scaffold.

The previous fragment of code would be an example of configuring a component with the $components array. You can also create your own components. you should consider creating your own component to contain the functionality. 'session')) ). All core components allow their configuration settings to be set in this way. you can configure components in your controller’s beforeFilter() method.CakePHP Cookbook Documentation. The above could also be expressed as: public function beforeFilter() { $this->Auth->authorize = array('controller'). 'action' => 'login' ) ).Toolbar' => array('panels' => array('history'. some components allow configuration options be set in the $components array: public $components = array( 'DebugKit. Controllers . 80 Chapter 4. } It’s possible. Release 2. 'loginAction' => array( 'controller' => 'users'. In addition. $this->Cookie->name = 'CookieMonster'. Configuration for these components. Configuring Components Many of the core components require configuration. To this end.x Components Components are packages of logic that are shared between controllers. is usually done in the $components array or your controller’s beforeFilter() method: class PostsController extends AppController { public $components = array( 'Auth' => array( 'authorize' => array('controller'). Each of the core components is detailed in its own chapter. $this->Auth->loginAction = array( 'controller' => 'users'. Creating components keeps controller code clean and allows you to reuse code between projects. This section describes how to configure and use components. 'Cookie' => array('name' => 'CookieMonster') ). and how to create your own components. CakePHP comes with a fantastic set of core components you can use to aid in various common tasks. Some examples of components requiring configuration are Authentication and Cookie. and for components in general. See Components. however. 'action' => 'login' ). This is useful when you need to assign the results of a function to a component property. If you find yourself wanting to copy and paste things between controllers. that a component requires certain configuration options to be set before the controller’s beforeFilter() is run.

Release 2. Note: Aliasing a component replaces that instance anywhere that component is used.CakePHP Cookbook Documentation. 'Controller/Component'). class MyAuthComponent extends AuthComponent { // Add your code to override the core AuthComponent } The above would alias MyAuthComponent to $this->Auth in your controllers. 'Cookie'). } // app/Controller/Component/MyAuthComponent. Be sure to not give a component and a model the same name. which allows you to alias components. public function delete() { if ($this->Post->delete($this->request->data('Post.'). Each component you use is exposed as a property on your controller.php class PostsController extends AppController { public $components = array( 'Auth' => array( 'className' => 'MyAuth' ) ). If you had loaded up the SessionComponent and the CookieComponent in your controller.id')) { $this->Session->setFlash('Post deleted.x Consult the relevant documentation to determine what configuration options each component provides. you could access them like so: class PostsController extends AppController { public $components = array('Session'.php App::uses('AuthComponent'. } } Note: Since both Models and Components are added to Controllers as properties they share the same ‘namespace’. This feature is useful when you want to replace $this->Auth or another common Component reference with a custom implementation: // app/Controller/PostsController. including inside other Components. Using Components Once you’ve included some components in your controller. One common setting to use is the className option. using them is pretty simple. return $this->redirect(array('action' => 'index')). From inside a controller’s method you More on controllers 81 . In situations like this you can load a component at runtime using the Component Collection. Loading components on the fly You might not need all of your components available on every controller action.

Controllers . The basic structure for the component would look something like this: App::uses('Component'.x can do the following: $this->OneTimer = $this->Components->load('OneTimer'). Failing to do this will trigger an exception. See the base Component API for more information on the callbacks components offer. So there is no need to re-declare the same component twice.CakePHP Cookbook Documentation. as well as the standard $this->Session */ public $components = array('Math'. 'Controller'). Release 2. class MathComponent extends Component { public function doComplexOperation($amount1. 'Session'). Component Callbacks Components also offer a few request life-cycle callbacks that allow them to augment the request cycle. 82 Chapter 4. through which we can access an instance of it: /* Make the new component available at $this->Math. The controller will automatically be given a new attribute named after the component. $this->OneTimer->getTime(). } } Note: All components must extend Component. Create the file in app/Controller/Component/MathComponent. Creating a Component Suppose our online application needs to perform a complex mathematical operation in many different parts of the application. Note: Keep in mind that loading a component on the fly will not call its initialize method.php. The first step is to create a new component file and class. Components declared in AppController will be merged with those in your other controllers. Including your component in your controllers Once our component is finished. $amount2) { return $amount1 + $amount2. If the component you are calling has this method you will need to call it manually after load. we can use it in the application’s controllers by placing the component’s name (without the “Component” part) in the controller’s $components array. We could create a component to house this shared logic for use in many different controllers.

x When including Components in a Controller you can also declare a set of parameters that will be passed on to the Component’s constructor. In this case you can include other components in your component the exact same way you include them in controllers . 'Session'.... } } Note: In contrast to a component included in a controller no callbacks will be triggered on a component’s component. 'randomGenerator' => 'srand' ). } public function bar() { // . if array keys match component’s public properties. The above would pass the array containing precision and randomGenerator to MathComponent::__construct() as the second parameter. public function initialize(Controller $controller) { $this->Existing->foo(). Using other Components in your Component Sometimes one of your components may need to use another component. 'Auth' ). 'Controller'). More on controllers 83 . Release 2. These parameters can then be handled by the Component: public $components = array( 'Math' => array( 'precision' => 2.php App::uses('Component'. the properties will be set to the values of these keys. class CustomComponent extends Component { // the other component your component uses public $components = array('Existing').using the $components var: // app/Controller/Component/CustomComponent. By convention. 'Controller').php App::uses('Component'. class ExistingComponent extends Component { public function foo() { // . } } // app/Controller/Component/ExistingComponent..CakePHP Cookbook Documentation.

$status and $exit variables have same meaning as for the controller’s method. $url. Release 2.CakePHP Cookbook Documentation.x Component API class Component The base Component class offers a few methods for lazily loading other Components through ComponentCollection as well as dealing with common handling of settings. Component::startup(Controller $controller) Is called after the controller’s beforeFilter method but before the controller executes the current action handler. $settings = array()) Constructor for the base component class. Component::beforeRender(Controller $controller) Is called after the controller executes the requested action’s logic. Component::beforeRedirect(Controller $controller. Controllers . The $url. Component::shutdown(Controller $controller) Is called before output is sent to the browser. All $settings that are also public properties will have their values changed to the matching value in $settings. It also provides prototypes for all the component callbacks. 84 Chapter 4. Callbacks Component::initialize(Controller $controller) Is called before the controller’s beforeFilter method. $exit=true) Is invoked when the controller’s redirect method is called but before any further action. $status=null. Component::__construct(ComponentCollection $collection. If this method returns false the controller will not continue on to redirect the request. You can also return a string which will be interpreted as the URL to redirect to or return an associative array with the key ‘url’ and optionally ‘status’ and ‘exit’. but before the controller’s renders views and layout.

XML. Often this is in the form of HTML. The view layer in CakePHP can be made up of a number of different parts.ctp (CakePHP Template). CakePHP comes with a few built-in View classes for handling the most common rendering scenarios: • To create XML or JSON webservices you can use the JSON and XML views. and will be covered in this chapter: • views: Views are the part of the page that is unique to the action being run.CHAPTER 5 Views Views are the V in MVC. Most of the time your views will be showing (X)HTML documents to browsers. • To serve protected files. They form the meat of your application’s response. It has a filename corresponding to its action. View Templates The view layer of CakePHP is how you speak to your users. or dynamically generated files. By default CakePHP view files are written in plain PHP and have a default extension of . or Smarty. • elements: smaller. For example. These files contain all the presentational logic needed to get the data it received from the controller in a format that is ready for the audience you’re serving to. A view file is stored in /app/View/. or JSON. reusable bits of view code. 85 . Elements are usually rendered inside views. you can use Themes. Each part has different uses. Views are responsible for generating the specific output required for the request. but streaming files and creating PDFs that users can download are also responsibilities of the View Layer. but you might also need to serve AMF data to a Flash object. the view file for the Products controller’s “view()” action would normally be found in /app/View/Products/view. or output a CSV file for a user. a subclass of View will bridge your templating language and CakePHP. If you’d prefer using a templating language like Twig. reply to a remote application via SOAP. • To create multiple themed views.ctp. you can use Sending files. in a subfolder named after the controller that uses the file.

It expects that the view extending it will define the sidebar and title blocks. Extending Views New in version 2. or serve RSS feeds. Most views are rendered inside a layout.1.ctp <h1><?php echo $this->fetch('title'). paginate model data. $post['Post']['id'] )). View extending allows you to wrap one view in another. you can avoid repeating the common markup for your sidebar. Views . <?php echo h($post['Post']['body']). The content block is a special block that CakePHP creates. • helpers: these classes encapsulate view logic that is needed in many places in the view layer. Among other things. array( 'action' => 'edit'. Assuming our view file has a $post variable with the data about our post. ?> // The remaining content will be available as the 'content' block // in the parent view. It will contain all the uncaptured content from the extending view. $post). $this->start('sidebar'). 86 Chapter 5. By extending a common view file.x • layouts: view files that contain presentational code that wraps many interfaces in your application. Combining this with view blocks gives you a powerful way to keep your views DRY. your application has a sidebar that needs to change depending on the specific view being rendered.CakePHP Cookbook Documentation. ?></h1> <?php echo $this->fetch('content').ctp $this->extend('/Common/view'). build AJAX functionality. Release 2. the view could look like: <?php // app/View/Posts/view. ?> <li> <?php echo $this->Html->link('edit'. ?> <div class="actions"> <h3>Related actions</h3> <ul> <?php echo $this->fetch('sidebar'). helpers in CakePHP can help you build forms. For example. ?> </li> <?php $this->end(). and only define the parts that change: // app/View/Common/view. $this->assign('title'. ?> </ul> </div> The above view file could be used as a parent view.

Blocks can be defined in two ways: either as a capturing block.x The post view above shows how you can extend a view. The above will result in /Common/index. echo $this->element('sidebar/popular_topics'). Each parent view will get the previous view’s content as the content block. In 2. When a view contains a call to extend(). blocks are ideal for implementing things such as sidebars.1. Using view blocks New in version 2. Each view can extend another view if desired. echo $this->element('sidebar/recent_topics'). $this->end(). Using view blocks 87 .3. You can nest extended views as many times as necessary. The start(). ''). Note: You should avoid using content as a block name in your application. You can also append into a block using start() multiple times. Calling extend() more than once in a view file will override the parent view that will be processed next: $this->extend('/Common/view'). append() and end() methods allow you to work with capturing blocks: // Create the sidebar block. a few new methods were added for working with blocks. and populate a set of blocks.ctp being rendered as the parent view to the current view. assign() can be used to clear or overwrite a block at any time: // Clear the previous content from the sidebar block. Release 2. CakePHP uses this for uncaptured content in extended views. $this->end(). Once it is complete. the extended view will be rendered. or regions to load assets at the bottom/top of the layout. $this->extend('/Common/index'). For example. $this->start('sidebar'). or by direct assignment. The prepend() method was added to prepend content to an existing block: // Prepend to sidebar $this->prepend('sidebar'. Any content not already in a defined block will be captured and put into a special block named content. $this->assign('sidebar'. echo $this->element('sidebar/recent_comments'). // Append into the sidebar later on. View blocks replace $scripts_for_layout and provide a flexible API that allows you to define slots or blocks in your views/layouts that will be defined elsewhere. 'this content goes on top of sidebar').CakePHP Cookbook Documentation. execution continues to the bottom of the current view file. $this->append('sidebar').

the navbar block will only contain the content added in the first section. You can display blocks using the fetch() method.CakePHP Cookbook Documentation. You can provide a default value using the second argument: <div class="shopping-cart"> <h3>Your Cart</h3> 88 Chapter 5. Displaying blocks New in version 2.show this instead</p> $this->end(). echo $this->element('notifications'). ?> the block is not defined by now . $this->end(). you can also provide a default value for a block should it not have any content. ?> </div> <?php endif.x The method startIfEmpty() can be used to start a block only if it is empty or undefined. ?> As of 2. // In <?php <p>If <?php a parent view/layout $this->startIfEmpty('navbar').1. the default content with the <p> tag will be discarded. the captured content will be discarded. This is useful when you want to conditionally define default content for a block if it does not already exist: // In a view file. If the block already exists. Note: You should avoid using content as a block name. // Create a navbar block $this->startIfEmpty('navbar'). Release 2. Views .3. returning ‘’ if a block does not exist: echo $this->fetch('sidebar').0. This is helpful in layouts. or extended views where you want to conditionally show headings or other markup: // In app/View/Layouts/default. This allows you to easily add placeholder content for empty states. fetch() will safely output a block. echo $this->element('navbar'). This is used by CakePHP internally for extended views. You can also use fetch to conditionally show content that should surround a block should it exist. ?> // Somewhere later in the parent view/layout echo $this->fetch('navbar'). In the above example. and view content in the layout. Since the block was defined in the child view.ctp <?php if ($this->fetch('menu')): ?> <div class="menu"> <h3>Menu options</h3> <?php echo $this->fetch('menu').

array('inline' => false)). Release 2. ?> </div> Changed in version 2. Instead you should use blocks.3: The $default argument was added in 2.3. To do so. array('block' => 'scriptBottom')). ?> // In your layout file. 'Your cart is empty'). When you create a layout. <!DOCTYPE html> <html lang="en"> <head> <title><?php echo $this->fetch('title'). then this is the right place to start. ?> </head> // Rest of the layout follows The HtmlHelper also allows you to control which block the scripts and CSS go to: // In your view $this->Html->script('carousel'. Anything you want to see in all of your views should be placed in a layout. make sure your layout includes a place for $this->fetch(’content’) Here’s an example of what a default layout might look like: Layouts 89 .1.CakePHP Cookbook Documentation. $this->Html->css('carousel'. Using blocks for script and CSS files New in version 2. Layouts A layout contains presentation code that wraps around a view.x <?php echo $this->fetch('cart'. because controller-rendered view code is placed inside of the default layout when the page is rendered. and meta() methods each update a block with the same name when used with the inline = false option: <?php // In your view file $this->Html->script('carousel'. Other layout files should be placed in /app/View/Layouts. you need to tell CakePHP where to place the output of your views. Blocks replace the deprecated $scripts_for_layout layout variable.ctp. ?></title> <?php echo $this->fetch('script'). array('inline' => false)). CakePHP’s default layout is located at /app/View/Layouts/default. // In your layout echo $this->fetch('scriptBottom'). If you want to change the overall look of your application. The HtmlHelper ties into view blocks. ?> <?php echo $this->fetch('css'). css(). and its script().

Views . use $this->fetch(’title’) in your layout and $this->assign(’title’. (See API for more details on usage). Release 2. $title_for_layout contains the page title.Add a footer to each displayed page --> <div id="footer">. The content block contains the contents of the rendered view. ?> <!-.</div> </body> </html> Note: Prior to version 2. include it here --> <div id="header"> <div id="menu">. ?> </head> <body> <!-.ico" type="image/x-icon"> <!-. This variable is generated automatically.0 The script.5. and switch between them inside of your controller actions using the controller or view’s $layout property: 90 Chapter 5.x <!DOCTYPE html> <html lang="en"> <head> <title><?php echo $this->fetch('title')... specify ‘false’ for the ‘inline’ option to place the HTML source in a block with the same name.1. ?></title> <link rel="shortcut icon" href="favicon.. ’page title’) instead. Note: When using HtmlHelper::css() or HtmlHelper::script() in view files. Note: The $title_for_layout is deprecated as of 2. fetch(’css’) and fetch(’script’) are contained in the $scripts_for_layout variable in version 2.. echo $this->fetch('script').Here's where I want my views to be displayed --> <?php echo $this->fetch('content').CakePHP Cookbook Documentation.) --> <?php echo $this->fetch('meta').Include external files and scripts here (See HTML helper for more info. You can create as many layouts as you wish: just place them in the app/View/Layouts directory. but you can override it by setting it in your controller/view as you would any other view variable.If you'd like some sort of menu to show up on all of your views. Useful for including JavaScript and CSS files from views. fetch(’content’) is a replacement for $content_for_layout and lines fetch(’meta’). css and meta blocks contain any content defined in the views using the built-in HTML helper. method fetch() was not available.</div> </div> <!-. echo $this->fetch('css').

For example. xml. navigational controls. js. For example.x // From a controller public function admin_view() { // Stuff $this->layout = 'admin'. Three other layouts. $this->layout = 'default_small_ad'. you can use plugin syntax. 'View Active Users'). If you want to use a layout that exists in a plugin. Using layouts from plugins New in version 2.it’s an empty layout. extra menus. The Ajax layout is handy for crafting AJAX responses . CakePHP can help you repeat parts of your website that need to be reused.CakePHP Cookbook Documentation. to use the contact layout from the Contacts plugin: class UsersController extends AppController { public function view_active() { $this->layout = 'Contacts. } // From a view file $this->layout = 'loggedin'. Ads. Elements 91 . } public function view_image() { $this->layout = 'image'. I might create a new layout with the smaller advertising space and specify it as the layout for all controllers’ actions using something like: class UsersController extends AppController { public function view_active() { $this->set('title_for_layout'. sometimes in different places in the layout.) The flash layout is used for messages shown by Controller::flash() method. These reusable parts are called Elements. and rss. exist in the core for a quick and easy way to serve up content that isn’t text/html.1. Release 2. help boxes.contact'. (Most AJAX calls only require a bit of markup in return. rather than a fully-rendered interface. // Output user image } } CakePHP features two core layouts (besides CakePHP’s default layout) you can use in your own application: ‘ajax’ and ‘flash’. } } Elements Many applications have small blocks of presentation code that need to be repeated from page to page. if a section of my site included a smaller ad banner space.

this text is very helpful. array(). An example: echo $this->element('helpbox'. Elements live in the /app/View/Elements/ folder. array( "cache" => array('config' => 'short'. and callouts are often implemented in CakePHP as elements. and even within other elements. Views . Inside the element file. This enables your elements to perform in true MVC style. This gives you a great amount of flexibility to decide where and for how long elements are stored. array( "helptext" => "Oh. this text is very helpful. The options supported are ‘cache’ and ‘callbacks’. // Outputs "Oh. They can also help you re-use content fragments in your application.ctp filename extension. Element caching is facilitated through the Cache class. 92 Chapter 5.ctp echo $helptext. array( "helptext" => "This is passed to the element as $helptext". In the above example. which fetches view variables from a controller action and returns them as an array. array( // Uses the "long_view" cache configuration "cache" => "long_view". ). You can take full advantage of elements by using requestAction(). To cache different versions of the same element in an application. the /app/View/Elements/helpbox. // Set to true to have before/afterRender called for the element "callbacks" => true ) ). "foobar" => "This is passed to the element as $foobar". all the passed variables are available as members of the parameter array (in the same way that Controller::set() in the controller works with view files).ctp file can use the $helptext variable: // Inside app/View/Elements/helpbox." )). They are output using the element method of the view: echo $this->element('helpbox'). Release 2. provide a unique cache key value using the following format: $this->element('helpbox'. and have the . Elements can be used to make a view more readable. placing the rendering of repeating elements in its own file. You can configure elements to be stored in any Cache configuration you’ve set up.CakePHP Cookbook Documentation. in layouts. An element is basically a miniview that can be included in other views. Passing Variables into an Element You can pass data to an element through the element’s second argument: echo $this->element('helpbox'." The View::element() method also supports options for the element.x login forms. 'key' => 'unique value') ) ).

then call requestAction() inside the second parameter of element() to feed the element the view variables from your controller. If set to true.CakePHP Cookbook Documentation. 'config' => 'view_long') ). $posts). } $this->set('posts'. Release 2. if ($this->request->is('requested')) { return $posts. array('cache' => true)). A simple example of caching an element would be: echo $this->element('helpbox'. For example: echo $this->element( 'helpbox'. To get the latest five posts in an ordered list. To do this. ?> <ol> <?php foreach ($posts as $post): ?> <li><?php echo $post['Post']['title']. we would do something like the following: <h2>Latest Posts</h2> <?php $posts = $this->requestAction( 'posts/index/sort:created/direction:asc/limit:5' ). public function index() { $posts = $this->paginate(). array(). Otherwise. you can set which cache configuration should be used. Elements 93 . } } And then in the element we can access the paginated posts model. it will cache the element in the ‘default’ Cache configuration. be sure to set the ‘key’ parameter to a different name each time. This will prevent each successive call from overwriting the previous element() call’s cached result. ?></li> <?php endforeach. in your controller add something like the following for the Post example: class PostsController extends AppController { // .x Create a controller action that prepares the view variables for your elements. array('cache' => array('key' => 'first_use'. If you render the same element more than once in a view and have caching enabled. See Caching for more information on configuring Cache.. array('var' => $var).. ?> </ol> Caching Elements You can take advantage of CakePHP view caching if you supply a cache parameter. echo $this->element( 'helpbox'.

x): echo $this->element('helpbox'. array().CakePHP Cookbook Documentation. unless another plugin name is present. // and echo $this->element('Contacts. If your view is a part of a plugin. For example. or add additional custom view-rendering logic to your application. the plugin name will automatically be prefixed onto all elements used. echo $this->element('Contacts. • When referencing view class names you should omit the View suffix. Like most components of CakePHP. if you are in the ContactsController of the Contacts plugin. the following: echo $this->element('helpbox'). array('plugin' => 'Contacts')). 94 For example: Chapter 5.1: The $options[plugin] option was deprecated and support for Plugin. use the plugin option (moved out of the data option in 1.helpbox'). Release 2. Changed in version 2. Views .element was added. Requesting Elements from a Plugin 2. CakePHP will use this configuration when none is given.helpbox'). For example: App/View/PdfView. it will look in the main APP folder. If you want all element caching to use the same cache configuration. The above will ensure that both element results are cached separately. just use the familiar plugin syntax. you can avoid some repetition by setting View::$elementCache to the cache configuration you want to use. For example: PdfView. 2. view classes have a few conventions: • View class files should be put in App/View. If the element doesn’t exist in the plugin.1 If you are using a plugin and wish to use elements from within the plugin. $this->viewClass = ’Pdf’. are equivalent and will result in the same element being rendered. Creating your own view classes You may need to create custom view classes to enable new types of data views. 'config' => 'view_long') ).0 To load an element from a plugin.php • View classes should be suffixed with View. array('cache' => array('key' => 'second_use'.. If the view is being rendered for a plugin controller/action. you can omit the plugin name.x array('var' => $differenVar).

the $activeMenuButton variable will be available and contain the value ‘posts’. Changed in version 2. array $options = array()) Renders an element or view partial. element and layout files. 'posts'). $default = null) Get the value of a viewVar with the name $var. mixed $url) Generates a unique non-random DOM ID for an object. View::get(string $var.3: Use View::get() instead. $this->method() To call any view method use View::set(string $var. See Controller Methods for more information on using set(). View::getVar(string $var) Gets the value of the viewVar with the name $var. As of 2.php App::uses('View'. Using set() from your view file will add the variables to the layout and elements that will be rendered later. This View API 95 .5: The $default argument was added in 2.5. class PdfView extends View { public function render($view = null. View API class View View methods are accessible in all view. 'View'). View::uuid(string $object. In your view file you can do: $this->set('activeMenuButton'. View::getVars() Gets a list of all the available view variables in the current rendering scope.CakePHP Cookbook Documentation. Then. mixed $value) Views have a set() method that is analogous to the set() found in Controller objects. Returns an array of variable names. in your layout. See the section on Elements for more information and examples. Deprecated since version 2. Release 2.x You’ll also want to extend View to ensure things work correctly: // In App/View/PdfView. array $data. you can provide a default value in case the variable is not already set.5. } } Replacing the render method lets you take full control over how your content is rendered. based on the object type and URL. View::element(string $elementPath. $layout = null) { // Custom logic here.

1. New in version 2. Views . Deprecated since version 2. New in version 2. string $content) Adds content to the internal scripts buffer. $default = ‘’) Fetch the value of a block. Release 2.3. $content) Assign the value of a block. array('controller' => 'posts'. View::fetch($name.x method is often used by helpers that need to generate unique DOM ID’s for elements such as the JsHelper: $uuid = $this->uuid( 'form'. See the section on Using view blocks for examples. See the section on Using view blocks for examples.CakePHP Cookbook Documentation. See the section on Using view blocks for examples. See the section on Using view blocks for examples. This method is most often used from inside helpers. New in version 2. such as the JsHelper and HtmlHelper Helpers. This method is helpful when creating helpers that need to add javascript or css directly to the layout. New in version 2. $content) Prepend to the block with $name. New in version 2. 96 Chapter 5. View::start($name) Start a capturing block for a view block. // $uuid contains 'form0425fe3bad' View::addScript(string $name. View::assign($name. See the section on Using view blocks for examples.1: Use the Using view blocks features instead. If a block is empty or undefined. Keep in mind that scripts added from the layout and elements in the layout will not be added to $scripts_for_layout. This buffer is made available in the layout as $scripts_for_layout.1. View::end() End the top most open capturing block. All content in the block will be captured and discarded if the block is already defined. This will overwrite any existing content. New in version 2. See the section on Using view blocks for examples. View::startIfEmpty($name) Start a block if it is empty.1.3. View::prepend($name. 'action' => 'index') ). View::append($name.1. ‘’ will be returned. $content) Append into the block with $name. View::blocks() Get the names of all defined blocks as an array.

2.1. To use themes. Within the themed folder. Setting this property will change the default configuration used to cache elements. property View::$request An instance of CakeRequest. New in version 2. More about Views Themes You can take advantage of themes. create a folder using the same name as your theme name. Deprecated since version 2. the above theme would be found in /app/View/Themed/AnotherExample. } Changed in version 2. New in version 2. More about Views 97 . Release 2. For example. property View::$output Contains the last rendered content from a view.1 removes this requirement as the normal View class supports themes You can also set or change the theme name within an action or within the beforeFilter or beforeRender callback functions: $this->theme = 'AnotherExample'. either the view file.1 required setting the $this->viewClass = ’Theme’.1.1: Use $view->Blocks->get(’content’). This default can be overridden using the ‘cache’ option in the element method. making it easy to switch the look and feel of your page quickly and easily. See the section on Extending Views for examples. property View::$elementCache The cache configuration used to cache elements. Use this instance to access information about the current request. Used to provide view block functionality in view rendering. specify the theme name in your controller: class ExampleController extends AppController { public $theme = 'Example'. instead.1: Versions previous to 2. View::extend($name) Extend the current view/element/layout with the named one. or the layout content. Theme view files need to be within the /app/View/Themed/ folder.1.CakePHP Cookbook Documentation.x New in version 2. property View::$layout Set the layout the current view will be wrapped in. property View::$Blocks An instance of ViewBlock.

To use the new theme webroot create directories like: app/View/Themed/<themeName>/webroot<path_to_file> in your theme. the folder structure within the /app/View/Themed/Example/ folder is exactly the same as /app/View/.css //and links to app/View/Themed/PurpleCupcake/webroot/css/main. A theme can include any necessary assets in its webroot directory. Layout files would reside in /app/View/Themed/Example/Layouts/.x Note: It is important to remember that CakePHP expects CamelCase theme names. if a file isn’t in the theme folder.js app/webroot/debug_kit/js/my_file.CakePHP Cookbook Documentation. In these situations it’s recommended that you either symlink or copy out plugin/theme assets to directories in app/webroot with paths matching those used by CakePHP. This allows for easy packaging and distribution of themes. CakePHP will try to locate the view file in the /app/View/ folder. Release 2. And while the core team has taken steps to make plugin and theme asset serving as fast as possible.css Increasing performance of plugin and theme assets It’s a well known fact that serving assets through PHP is guaranteed to be slower than serving those assets without invoking PHP. The Dispatcher will handle finding the correct theme assets in your view paths.js 98 becomes Chapter 5. there may be situations where more performance is required. All of CakePHP’s built-in helpers are aware of themes and will create the correct paths automatically. Beyond that. If a view file can’t be found in the theme. you can create master view files and simply override them on a case-by-case basis within your theme folder. it’s recommended that you either symlink or copy theme assets into the application’s webroot. Like view files. //creates a path like /theme/purple_cupcake/css/main. Views . Theme assets Themes can contain static assets as well as view files. it will default to the main webroot folder: //When in a theme with the name of 'purple_cupcake' $this->Html->css('main. the view file for an edit action of a Posts controller would reside at /app/View/Themed/Example/Posts/edit.css'). requests for theme assets will be handled by Dispatcher.ctp. • app/Plugin/DebugKit/webroot/js/my_file. This way. To improve performance for production environments. See below for more information. While in development. For example.

CakePHP Cookbook Documentation. 'path' => APP . // Download app/outside_webroot_dir/example. DS ). just pass in additional parameters to specify where your file is located: class ExampleController extends AppController { public function download() { $this->viewClass = 'Media'. 'outside_webroot_dir' .css becomes Media Views class MediaView Deprecated since version 2. To use the Media view.zip $params = array( 'id' => 'example. 'name' => 'example'. 'extension' => 'docx'.css app/webroot/theme/Navy/css/navy.document' ). 'mimeType' => array( 'docx' => 'application/vnd. 'name' => 'example'. you may wish to have a directory of files outside of the webroot to prevent users from direct linking them. you need to tell your controller to use the MediaView class instead of the default View class. } More about Views 99 . Media views allow you to send binary files to the user. We are also using a relative path which will default to your app/webroot folder: public function download() { $this->viewClass = 'Media'. For example. } } Here’s an example of rendering a file whose mime type is not included in the MediaView’s $mimeType array. Release 2.x • app/View/Themed/Navy/webroot/css/navy. '. After that.openxmlformats-officedocument' . 'path' => 'files' .docx'.wordprocessingml.3: Use Sending files instead. You can use the Media view to pull the file from a special folder within /app/. $this->set($params).zip'. allowing you to perform authentication before delivering the file to the user. // Render app/webroot/files/example.docx $params = array( 'id' => 'example. $this->set($params). DS ). 'download' => true. 'extension' => 'zip'.

There are two ways you can generate data views. This will enable automatic view class switching on content types.CakePHP Cookbook Documentation. The path should be absolute but can be relative to the app/webroot folder. The XmlView and JsonView let you easily create XML and JSON responses. CakePHP will automatically switch view classes when a request is done with the . Add the RequestHandlerComponent to your controller’s list of components. extension The file extension. mimeType An array with additional mime types to be merged with MediaView internal list of acceptable mime types. New in version 2. This will enable Router to handle multiple extensions. Enable the json and or xml extensions with Router::parseExtensions(). to your routes file. By enabling RequestHandlerComponent in your application. If the mime type specified is not in the list (or set in the mimeType parameter array). path The folder name. you can automatically leverage the new view classes. including the final directory separator. This is matched against an internal list of acceptable mime types. 100 Chapter 5. You can also set the component up with the viewClassMap setting. Specify the name without the file extension. name The name allows you to specify an alternate file name to be sent to the user. After adding Router::parseExtensions(’json’). you’ll need to do a bit of setup: 1. The viewClassMap setting will not work on earlier versions.x Settable Parameters id The ID is the file name as it resides on the file server including the file extension. to map types to your custom classes and/or map other data types. the file will not be downloaded. 2. Enabling data views in your application Before you can use the data view classes. and integrate with the RequestHandlerComponent. Release 2. The first is by using the _serialize key. JSON and XML views New in CakePHP 2. download A boolean value indicating whether headers should be set to force download. otherwise set it to the number of seconds in the future for when the cache should expire.json extension. XmlView and JsonView will be referred to as data views for the rest of this page.3: RequestHandlerComponent::viewClassMap() method has been added to map types to viewClasses. or the Accept header is application/json. and enabling support for the xml and or json extensions. Views .If set to true it will allow browsers to cache the file (defaults to false if not set). cache A boolean or integer value .1 are two new view classes. and the second is by creating normal view files.

array('posts')). } } // View code . For example if we had posts. 'comments')). array('posts'. you should use view files.ctp foreach ($posts as &$post) { unset($post['Post']['generated_html']). $this->set('_serialize'. This lets you skip defining view files for your controller actions if you don’t need to do any custom formatting before your data is converted into json/xml. 'comments')). Release 2. we would probably want to omit that from a JSON response. public function index() { // some code that created $posts and $comments $this->set(compact('posts'.CakePHP Cookbook Documentation. that had a field containing generated HTML. If you need to do any formatting or manipulation of your view variables before generating the response. 'comments')). Using a data view with view files You should use view files if you need to do some manipulation of your view content before creating the final output. If you use a string value for _serialize and XmlView. public function index() { $this->set('posts'. } } You can also define _serialize as an array of view variables to combine: class PostsController extends AppController { public $components = array('RequestHandler'). The value of _serialize can be either a string or an array of view variables to serialize: class PostsController extends AppController { public $components = array('RequestHandler').app/View/Posts/json/index. make sure that your view variable has a single top-level element.x Using data views with the serialize key The _serialize key is a special view variable that indicates which other view variable(s) should be serialized when using a data view. This is a situation where a view file would be useful: // Controller code class PostsController extends AppController { public function index() { $this->set(compact('posts'. Without a single top-level element the Xml will fail to generate. } } Defining _serialize as an array has the added benefit of automatically appending a top-level <response> element when using XmlView. More about Views 101 . $this->Paginator->paginate()). $this->set('_serialize'.

times and numbers. This allows you to configure the bit-mask options used when generating JSON. and can even speed up AJAX functionality. JSONP response New in version 2. New in version 2. See above for how you can use JsonView in your application. You can set a custom name for this node using the _rootNode view variable.6: The XmlView class supports the _xmlOptions variable that allows you to customize the options used to generate XML. array $settings = array()) 102 Chapter 5. Helpers Helpers are the component-like classes for the presentation layer of your application. and outline the basic tasks CakePHP’s core helpers can help you accomplish. This chapter will show you how to create your own helpers.4. elements. You can do more complex manipulations. Note: The data view classes don’t support layouts. CakePHP features a number of helpers that aid in view creation. tags vs attributes. Release 2.x } echo json_encode(compact('posts'. For more information on the helpers included in CakePHP. They assume that the view file will output the serialized content.3: The _rootNode feature was added. When using JsonView you can use the special view variable _jsonp to enable returning a JSONP response. See above for how you can use XmlView in your application. check out the chapter for each helper: CacheHelper class CacheHelper(View $view.g. class XmlView A view class for generating Xml view data. New in version 2. aid in formatting text.6: JsonView now supports the _jsonOptions view variable. e.CakePHP Cookbook Documentation. Views . Setting it to true makes the view class check if query string parameter named “callback” is set and if so wrap the json response in the function name provided. They contain presentational logic that is shared between many views. They assist in creating well-formed markup (including forms). or use helpers to do formatting as well. or layouts. By default when using _serialize the XmlView will wrap your serialized view variables with a <response> node. 'comments')). If you want to use a custom query string parameter name instead of “callback” set _jsonp to required name instead of true. class JsonView A view class for generating Json view data. New in version 2.

the rest of the URL dispatching process is skipped. $cacheAction should be set to an array which contains the actions you want cached. a view is marked with cache tags indicating which blocks of content should not be cached. Using the Helper There are two steps you have to take before you can use the CacheHelper.viewPrefix’. that receives a lot of traffic that needs to be cached: public $cacheAction = array( 'view' => 36000. It does not have methods that are directly called.CakePHP Cookbook Documentation.check. The CacheHelper then uses helper callbacks to process the file and output to generate the cache file. “1 hour”.x The Cache helper assists in caching entire layouts and views. If it has. or “3 minutes”). and the duration in seconds you want those views cached.check line you will need to add the helper to your controller’s $helpers array: class PostsController extends AppController { public $helpers = array('Cache'). Once you’ve uncommented the Cache. 'index' => 48000 ). Instead. Release 2. When a URL is requested. New in version 2. Any nocache blocks are processed normally and the view is served. By making $cacheAction a strtotime() friendly value you can cache every action in the controller: More about Views 103 . Additional configuration options CacheHelper has a few additional configuration options you can use to tune and tweak its behavior. } You will also need to add the CacheDispatcher to your dispatcher filters in your bootstrap: Configure::write('Dispatcher. If CakePHP doesn’t find a cached view. to store the view cache files prefixed. This will cache the view action 10 hours. First in your APP/Config/core.g. or the cache has expired for the requested URL it continues to process the request normally. ‘YOURPREFIX’). This will tell CakePHP to check for. The time value can be expressed in a strtotime() format (e. array( 'CacheDispatcher' )). Using the example of an ArticlesController.3: If you have a setup with multiple domains or languages you can use Configure::write(‘Cache. CakePHP checks to see if that request string has already been cached.php uncomment the Configure write call for Cache. saving time repetitively retrieving data. and generate view cache files when handling requests. This is done through the $cacheAction variable in your controllers. This creates a big savings in processing time for each request to a cached URL as minimal code is executed. View Caching in CakePHP temporarily stores parsed layouts and views as simple PHP + HTML files.filters'. It should be noted that the Cache helper works quite differently than other helpers. and the index action 13 hours.

This is also the reason it is disabled by default. 'users/login'). 'duration' => 48000) ). Release 2. Clearing the Cache It is important to remember that CakePHP will clear a cached view if a model used in the cached view is modified. To indicate blocks of content that are not to be cached. 'index' => array('callbacks' => true. if a cached view uses data from the Post model. and view variables are serialized with PHP’s serialize(). For example. 104 Chapter 5. 'add' => array('callbacks' => true. ?>. certain parts of the page may look different whether a user is currently logged in or browsing your site as a guest. the controller method for the action will not be called. and component startup callbacks. the request object.name')). resource handles. ?> <!--/nocache--> Note: You cannot use nocache tags in elements. fire the component initialize. By setting callbacks => true you tell CacheHelper that you want the generated files to create the components and models for the controller. wrap them in <!--nocache--> <!--/nocache--> like so: <!--nocache--> <?php if ($this->Session->check('User. Views . 'duration' => 21600). Marking Non-Cached Content in Views There will be times when you don’t want an entire view cached. they cannot be cached. ?> <?php endif. controller beforeFilter. <?php echo h($this->Session->read('User. 'duration' => 36000). Additionally. <?php else: ?> <?php echo $this->Html->link('Login'. Note: Setting callbacks => true partly defeats the purpose of caching. You can also enable controller/component callbacks for cached views created with CacheHelper. For example. It should be noted that once an action is cached. When a cache file is created. To do so you must use the array format for $cacheAction and create an array like the following: public $cacheAction = array( 'view' => array('callbacks' => true. and there has been an INSERT.name')): ?> Welcome. Warning: If you have view variables that contain un-serializable content such as SimpleXML objects.CakePHP Cookbook Documentation. Since there are no callbacks around elements.x public $cacheAction = "1 hour". or closures you might not be able to use view caching.

x UPDATE. More about Views 105 . you can specify which flash key to render: <?php echo $this->Flash->render('other') ?> You can also override any of the options that were set in FlashComponent: // In your Controller $this->Flash->set('The user has been saved. you can simply use FlashHelper’s render() method: <?php echo $this->Flash->render() ?> By default. if you’ve specified a key when setting the flash message in FlashComponent. please refer to the FlashComponent section. For more information about the available array options. If you’ve used routing to change your URLs this feature will not work. excluding cached view files. This will clear all cached data. Note: This automatic cache clearing requires the controller/model name to be part of the URL. CakePHP uses a “flash” key for flash messages in a session.'. If you need to clear the cached view files. or DELETE query made to a Post. you should escape it with h when formatting your messages.ctp and error. use clearCache(). Flash elements are found under the app/View/Elements/Flash directory. The FlashHelper replaces the flash() method on SessionHelper and should be used instead of that method.CakePHP Cookbook Documentation. Note: By default. You’ll notice that CakePHP’s App template comes with two flash elements: success.ctp instead of success. the cache for that view is cleared. array $config = array()) FlashHelper provides a way to render flash messages that were set in $_SESSION by FlashComponent.ctp. But. If you need to manually clear the cache. // In your View: Will use great_success. FlashComponent and FlashHelper primarily use elements to render flash messages. array( 'element' => 'great_success' )). Rendering Flash Messages To render a flash message. Release 2. FlashHelper class FlashHelper(View $view. CakePHP does not escape the HTML in flash messages. array( 'element' => 'success' )). you can do so by calling Cache::clear(). and new content is generated on the next request.ctp <?php echo $this->Flash->render('flash'. If you are using any request or user data in your flash messages.

in a way that will streamline validation. The default method for form submission is POST. Output: <form id="RecipeAddForm" method="post" action="/recipes/add"> This will POST the form data to the add() action of RecipesController. By specifying a model for a form. then it assumes you are using the default model for the current controller: // If you are on /recipes/add echo $this->Form->create('Recipe'). via the current URL. re-population and layout. if we browse to http://site.x FormHelper class FormHelper(View $view. All fields are assumed to belong to this model (unless otherwise specified). however. array $settings = array()) The FormHelper does most of the heavy lifting in form creation. array $options = array()) All parameters are optional. The ID is generated using the name of the model. Views . and that array contains a non-empty value of the model’s primary key. we would get the following: 106 Chapter 5. If I were to call create() inside a UsersController view. The form element is also returned with a DOM ID. FormHelper::create(string $model = null. If create() is called with no parameters supplied. If you do not specify a model. The FormHelper is also flexible . Release 2. or you can use specific methods to get only what you need. The FormHelper uses the $this->request->data property to automatically detect whether to create an add or edit form. This special method outputs an opening form tag. then the FormHelper will create an edit form for that record. I’d see something like the following output in the rendered view: <form id="UserAddForm" method="post" action="/users/add"> Note: You can also pass false for $model. First. it assumes you are building a form that submits to the current controller. This will place your form data into the array: $this->request->data (instead of in the sub-array: $this->request->data[’Model’]). you are creating that form’s context.com/recipes/edit/5. Creating Forms The first method you’ll need to use in order to take advantage of the FormHelper is create(). The FormHelper focuses on creating forms quickly.it will do almost everything for you using conventions. CamelCased. However. you can specify a model name. For example. and the name of the controller action. The create() method allows us to customize much more using the parameters. This can be handy for short forms that may not represent anything in your database. and all models referenced are assumed to be associated with it. you can also use the same logic to create an edit form.CakePHP Cookbook Documentation. If $this->request->data contains an array element named after the form’s model.

is now the current URL including passed. This is to be used if there are any file elements inside the form. This special array can contain a number of different key-value pairs that affect the way the form tag is generated. you should always use plugin syntax when creating a form. Output: <form id="UserAddForm" method="get" action="/users/add"> Specifying ‘file’ changes the form submission method to ‘post’. ‘put’ and ‘delete’. ‘get’. The $options array is where most of the form configuration happens. The absence of the proper enctype attribute will cause the file uploads not to function: More about Views 107 . ?> Output: <form id="RecipeEditForm" method="post" action="/recipes/edit/5"> <input type="hidden" name="_method" value="PUT" /> Note: Since this is an edit form.Contact'). Valid values include ‘post’. When creating forms for models in plugins.0: The default URL for all forms.php: public function edit($id = null) { if (empty($this->request->data)) { $this->request->data = $this->Recipe->findById($id). and includes an enctype of “multipart/form-data” on the form tag. array('type' => 'get')).CakePHP Cookbook Documentation. // we will get an edit form <?php echo $this->Form->create('Recipe'). ‘file’. a hidden input field is generated to override the default HTTP method.ctp: // Since $this->request->data['Recipe']['id'] = 5. You can override this default by supplying $options[’url’] in the second parameter of $this->Form->create(). } else { // Save logic goes here } } // View/Recipes/edit. Release 2. Changed in version 2. Options for create() There are a number of options for create(): • $options[’type’] This key is used to specify the type of form to be created. named. This will ensure the form is correctly generated: echo $this->Form->create('ContactManager. Supplying either ‘post’ or ‘get’ changes the form submission method accordingly: echo $this->Form->create('User'.x // Controller/RecipesController. and querystring parameters.

array( 'url' => 'http://www. • $options[’action’] The action key allows you to point the form to a specific action in your current controller. setting ‘default’ to false suppresses the form’s default behavior so you can grab the data and submit it via AJAX instead.x echo $this->Form->create('User'.com/search"> Also check HtmlHelper::url() method for more examples of different types of URLs. but when submitted. array( 'url' => array('controller' => 'recipes'. Output: <form method="post" action="/recipes/add"> or can point to an external domain: echo $this->Form->create(null. Release 2. the HTTP request method will be overridden with ‘PUT’ or ‘DELETE’.google. • $options[’default’] If ‘default’ has been set to boolean false. respectively. 'action' => 'add') )). If the form is meant to be submitted via AJAX. if you’d like to point the form to the login() action of the current controller. 'type' => 'get' )). The supplied URL can be relative to your CakePHP application: echo $this->Form->create(null. array('action' => 'login')). the form’s submit action is changed so that pressing the submit button does not submit the form. you can specify a URL for the form action using the ‘url’ key of the $options array.com/search'. For example.google. Output: <form id="UserAddForm" enctype="multipart/form-data" method="post" action="/users/add"> When using ‘put’ or ‘delete’. array('type' => 'file')). your form will be functionally equivalent to a ‘post’ form.CakePHP Cookbook Documentation. • $options[’inputDefaults’] You can declare a set of default options for input() with the inputDefaults key to customize your default input creation: 108 Chapter 5. This allows CakePHP to emulate proper REST support in web browsers. you would supply an $options array like the following: echo $this->Form->create('User'. Output: <form method="get" action="http://www. Views . Output: <form id="UserLoginForm" method="post" action="/users/login"> • $options[’url’] If the desired form action isn’t in the current controller.

array( 'inputDefaults' => array( 'label' => false. ?> Will output: <div class="submit"> <input type="submit" value="Finish" /> </div> </form> You can specify detail settings by passing an array to end(): $options = array( 'label' => 'Update'. 'div' => false ) )). Closing the Form FormHelper::end($options = null. echo $this->Form->end($options). 'div' => array( 'class' => 'glass-pill'. Often. ?> If a string is supplied as the first parameter to end(). More about Views 109 . Release 2. ) ).CakePHP Cookbook Documentation. // No div. end() only outputs a closing form tag. ?> <!-. no label // has a label element echo $this->Form->input( 'username'.x echo $this->Form->create('User'. array('label' => 'Username') ). but using end() also allows the FormHelper to insert needed hidden form elements that SecurityComponent requires: <?php echo $this->Form->create(). $secureAttributes = array()) The FormHelper includes an end() method that completes the form.Form elements go here --> <?php echo $this->Form->end(). the FormHelper outputs a submit button named accordingly along with the closing form tag: <?php echo $this->Form->end('Finish'). All inputs created from that point forward would inherit the options declared in inputDefaults. You can override the defaultOptions by declaring the option in the input() call: echo $this->Form->input('password').

org/2.x Will output: <div class="glass-pill"><input type="submit" value="Update" name="Update"> </div> See the Form Helper API1 for further details. and meridian selects time hour. with name of password. month. and year selects datetime. We’ll start by looking at input(). Creating form elements There are a few ways to create form inputs with the FormHelper.5. Release 2. etc. varchar.CakePHP Cookbook Documentation. month. with name of tel. year. or phone tel date day. tinyint(1) checkbox text textarea text. •Label element •Input element(s) •Error element with message if applicable. Note: If you are using SecurityComponent in your application you should always end your forms with end(). Changed in version 2. hour. minute. Views . passwd. minute.5: The $secureAttributes parameter was added in 2. array $options = array()) Creates the following elements given a particular Model. The type of input created depends on the column datatype: Column Type Resulting Form Field string (char. telephone. or psword password text. timestamp day. FormHelper::input(string $fieldName.) text boolean. Internally input() delegates to other methods in FormHelper. with name of email email text.8/class-FormHelper.field: •Wrapping div. This method will automatically inspect the model field it has been supplied in order to create an appropriate input for that field.html 110 Chapter 5.cakephp. and meridian selects binary file 1 http://api.

echo $this->Form->input('approved'). array( 'label' => 'Date of birth'. or ExtraFunkyModel -> extraFunkyModels) with the select options.70.x The $options parameter allows you to customize how input() works. month. Release 2. password (varchar). You can explicitly set required key in options array to override it for a field. 'minYear' => date('Y') . Assuming that User hasAndBelongsToMany Group. You can use the input() method of the FormHelper to create appropriate inputs for all of these form fields: echo $this->Form->create(). To skip browser validation triggering for the whole form you can set option ’formnovalidate’ => true for the input button you generate using FormHelper::submit() or set ’novalidate’ => true in options for FormHelper::create(). The wrapping div will have a required class name appended if the validation rules for the Model’s field do not specify allowEmpty => true. minute. And in the view a multiple select can be created with this simple code: echo $this->Form->input('Group'). set a camelCase plural variable (group -> groups in this case. 'maxYear' => date('Y') .18. New in version 2. 'dateFormat' => 'DMY'. echo $this->Form->input('password'). )).3.5: The binary type now maps to a file input.3 the HTML5 required attribute will also be added to the input based on validation rules. approved (datetime) and quote (text). year. let’s assume that your User model includes fields for a username (varchar). For example. and finely control what is generated. echo $this->Form->input('quote').CakePHP Cookbook Documentation. A more extensive example showing some options for a date field: echo $this->Form->input('birth_dt'. Besides the specific options for input() found below. you can specify any option for the input type & any HTML attribute (for instance onfocus). For more information on $options and $htmlAttributes see HtmlHelper. //text //password //day. //meridian //textarea echo $this->Form->end('Add'). Or be directly associated to the model supplied to create(). More about Views 111 . echo $this->Form->input('username'). hour. Since 2. New in version 2. In your controller. $this->User->Group->find('list')). In the controller action you would put the following: $this->set('groups'. One limitation of this behavior is the field’s model must have been loaded during this request.

inputs() allows you to use a few additional options.CakePHP Cookbook Documentation. you can add the following to your Users-controller (assuming your User belongsTo Group): $this->set('groups'. You can create inputs for associated models. // or $this->set( 'reallyInappropriateModelNames'. except of those defined in $blacklist. If a string is supplied it will be used as the class name for the fieldset element.x If you want to create a select field while using a belongsTo . $options = array()) Generate a set of inputs for $fields. when passing the data using set() you should name your data in a pluralised and camelCased format as follows: $this->set('userGroups'. Afterwards. In addition to controller fields output. Note: Try to avoid using FormHelper::input() to generate submit buttons.fieldname as the first parameter: 112 Chapter 5. add the following to your form-view: echo $this->Form->input('group_id').Relation. $this->User->Group->find('list')). •fieldset Set to false to disable the fieldset. If $fields is null all fields. $this->ReallyInappropriateModelName->find('list') ). $fields can be used to control legend and fieldset rendering with the fieldset and legend keys. or arbitrary models by passing in Modelname. •legend Set to false to disable the legend for the generated input set. Would generate an input set with a custom legend. FormHelper::submit() instead.. echo $this->Form->inputs(array( 'name' => array('label' => 'custom label') )). Field naming conventions The Form helper is pretty smart. array $blacklist = null. Use FormHelper::inputs(mixed $fields = null. You can customize individual inputs through $fields as well. $this->Form->inputs(array(’legend’ => ’My legend’)). of the current model will be used. e. If your model name consists of two or more words.g.or hasOne . “UserGroup”. $this->UserGroup->find('list')). it’ll automatically use the current model name to build an input with a format like the following: <input type="text" id="ModelnameFieldname" name="data[Modelname][fieldname]"> This allows you to omit the model name when generating inputs for the model that the form was created for. In addition to fields control. Views . Or supply a string to customize the legend text. Whenever you specify a field name with the form helper methods. Release 2.

0. Options FormHelper::input() supports a large number of options. or meridian and having issues getting the correct input.fieldname'). If you are using fields named year. overriding model introspection. you can also create ‘file’. echo $this->Form->input('Modelname. you can set the name attribute to override the default behavior: echo $this->Form->input('Model. In addition to the field types found in the Creating form elements. If you need to specify multiple fields using the same field name.x echo $this->Form->input('Modelname. Release 2.fieldname'). as well as HTML attributes. by specifying a type. Output: <input type="text" id="Modelname0Fieldname" name="data[Modelname][0][fieldname]"> <input type="text" id="Modelname1Fieldname" name="data[Modelname][1][fieldname]"> FormHelper uses several field-suffixes internally for datetime input creation. Using a string value will set the div’s class name. In addition to its own options input() accepts options for the generated input types.CakePHP Cookbook Documentation. 'name' => 'data[Model][year]' )).fieldname'). • $options[’type’] You can force the type of an input. month. hour.year'. day. minute. you can set this key to false to disable the output of the div. thus creating an array that can be saved in one shot with saveAll(). Alternatively. The following will cover the options specific to FormHelper::input(). array('type' => 'email')). An array will set the div’s attributes to those specified by the array’s keys/values. Output: <div class="input file"> <label for="UserField">Field</label> <input type="file" name="data[User][field]" value="" id="UserField" /> </div> <div class="input email"> <label for="UserEmail">Email</label> <input type="email" name="data[User][email]" value="" id="UserEmail" /> </div> • $options[’div’] Use this option to set attributes of the input’s containing div. Setting the class name: More about Views 113 . echo $this->Form->input('email'. array( 'type' => 'text'. use the following convention: echo $this->Form->input('Modelname. and any type supported by HTML5: echo $this->Form->input('field'. ‘password’. array('type' => 'file')).1.

Release 2. 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: echo $this->Form->input('User. 'title' => 'Div Title'.name'.CakePHP Cookbook Documentation. Output: <div class="class_name"> <label for="UserName">Name</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> Setting multiple attributes: echo $this->Form->input('User. array('div' => false)).name'. Views . set this key to false to disable the output of the label: 114 Chapter 5. ?> Output: <label for="UserName">Name</label> <input name="data[User][name]" type="text" value="" id="UserName" /> • $options[’label’] Set this key to the string you would like to be displayed within the label that usually accompanies the input: echo $this->Form->input('User. Output: <div class="input"> <label for="UserName">The User Alias</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> Alternatively.name'. array( 'label' => 'The User Alias' )). array( 'div' => array( 'id' => 'mainDiv'. array( 'div' => 'class_name' )).name'.x echo $this->Form->input('User. 'style' => 'display:block' ) )).

name'.field'. you can use a text key in the array to customize the label text: echo $this->Form->input('User. array('errorMessage' => false)). If you do this. Output: <div class="input"> <label for="UserName" class="thingy">The User Alias</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> • $options[’error’] Using this key allows you to override the default model error messages and can be used. array( 'label' => array( 'class' => 'thingy'. use the following format: $this->Form->input('Model.name'. More about Views 115 . for example. array('label' => false)).field'. array( 'error' => array( 'attributes' => array('escape' => 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.field'. and whether HTML in the error message will be escaped. To disable error message output & field classes set the error key to false: $this->Form->input('Model.field'.x echo $this->Form->input('User. array('error' => false)). 'class' => 'bzzz') ) )). but retain the field classes.CakePHP Cookbook Documentation. To prevent HTML being automatically escaped in the error message output. 'text' => 'The User Alias' ) )). set the errorMessage key to false: $this->Form->input('Model. To modify the wrapping element type and its class. It has a number of suboptions which control the wrapping element. wrapping element class name. to set i18n messages. array( 'error' => array( 'attributes' => array('wrap' => 'span'. Release 2. set the escape suboption to false: $this->Form->input('Model. To disable only the error message.

3 • $options[’before’]. 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> 116 Chapter 5. New in version 2. Views . $options[’separator’]. Output: <div class="input"> --before-<label for="UserField">Field</label> --between--<input name="data[User][field]" type="text" value="" id="UserField" /> --after-</div> For radio inputs the ‘separator’ attribute can be used to inject markup to separate each input/label pair: echo $this->Form->input('field'. As seen above you can set the error message for each validation rule you have in your models. 'options' => array('1'. 'separator' => '--separator--'.x To override the model error messages use an array with the keys matching the validation rule names: $this->Form->input('Model. and Use these keys if you need to inject some markup inside the output of the input() method: echo $this->Form->input('field'. array( 'before' => '--before--'. array( 'before' => '--before--'. 'between' => '--between---'. 'between' => '--between---' )). 'after' => '--after--'.field'. 'after' => '--after--'. array( 'error' => array('tooShort' => __('This is not long enough')) )).CakePHP Cookbook Documentation. Release 2. '2') )).3: Support for the errorMessage option was added in 2. In addition you can provide i18n messages for your forms. $options[’after’] $options[’between’].

More about Views 117 . If you need to later change the defaults you can use FormHelper::inputDefaults(). All inputs created from that point forward would inherit the options declared in inputDefaults.’error’).x For date and datetime type elements the ‘separator’ attribute can be used to change the string between select elements. Release 2. array( 'inputDefaults' => array( 'label' => false. no label echo $this->Form->input('password'). array('label' => 'Username')). // Makes <select name="Tags" multiple="multiple"> echo $this->Form->input('Tags. ’input’. ’between’. ’label’. array('multiple' => true)). array('name' => 'data[User][email]')). // has a label element echo $this->Form->input('username'. Defaults to ‘-‘. GET Form Inputs When using FormHelper to generate inputs for GET forms. the input names will automatically be shortened to provide more human friendly names.CakePHP Cookbook Documentation. For example: // Makes <input name="email" type="text" /> echo $this->Form->input('User. you can use inputDefaults‘ to keep your code dry: echo $this->Form->create('User'.Tags'. • $options[’format’] The ordering of the HTML generated by FormHelper is controllable as well. The ‘format’ options supports an array of strings describing the template you would like said element to follow. Generating specific types of inputs In addition to the generic input() method. The supported array keys are: array(’before’. FormHelper has specific methods for generating a number of different types of inputs. ’after’.email'. These can be used to generate just the input widget itself. 'div' => false ) )). • $options[’inputDefaults’] If you find yourself repeating the same options in multiple input() calls. and combined with other methods like label() and error() to generate fully custom form layouts. If you want to override the generated name attributes you can use the name option: // Makes the more typical <input name="data[User][email]" type="text" /> echo $this->Form->input('User.email'). You can override the defaultOptions by declaring the option in the input() call: // No div.

Release 2. For types select. array( 'type' => 'time'. array('default' => 'Sugar')). you can mixin any HTML attribute you wish to use. datetime). Set ‘selected’ to the value of the item you wish to be selected by default when the input is rendered: echo $this->Form->input('close_time'. • $options[’default’] Used to set a default value for the input field. 118 Chapter 5. so ’default’ => false would not set any value at all. echo $this->Form->input( 'size'. Beware of using false to assign a default value. Example with select field (Size “Medium” will be selected as default): $sizes = array('s' => 'Small'. Note: The selected key for date and datetime inputs may also be a UNIX timestamp. 'default' => 'm') ). date. Date and datetime fields’ default values can be set by using the ‘selected’ key. In addition to the above options. 'selected' => '13:30:00' )).instead you might set the value in $this->request->data in your controller. Note: You cannot use default to check a checkbox . A false value is used to disable/exclude options of an input field. 'l' => 'Large'). or set the input option checked to true. 'm' => 'Medium'. Views . • $options[’empty’] If set to true. array('class' => 'custom-class')). checkbox and radio inputs • $options[’selected’] Used in combination with a select-type input (i. and applied to the generated HTML input element. Any non-special option name will be treated as an HTML attribute. array('options' => $sizes. To reduce repetition the common options shared by all input methods are as follows: • $options[’class’] You can set the class name for an input: echo $this->Form->input('title'. All of these options are also supported by input(). Instead use ’default’ => 0.CakePHP Cookbook Documentation. • $options[’id’] Set this key to force the value of the DOM id for the input. 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). time. Options for select. forces the input to remain empty. Example usage: echo $this->Form->input('ingredient'.e.x Common options Many of the various input element methods support a common set of options.

. Release 2. A list of key-value pairs can be supplied for a date or datetime field: echo $this->Form->dateTime('Contact. pass in a string to empty: echo $this->Form->input('field'. 'meridian' => false ) ) ).. use ‘value’ => ‘’ instead. 'year' => 'YEAR'.CakePHP Cookbook Documentation. If you want to have a empty value with text displayed instead of just a blank option. <option value="31">31</option> </select> .date'.. 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> Note: If you need to set the default value in a password field to blank. this creates a blank option with an empty value in your drop down list. <option value="12">December</option> </select> .<select name="data[Contact][date][month]" id="ContactDateMonth"> <option value="">MONTH</option> <option value="01">January</option> // . '12'. 4.. 'hour' => 'HOUR'. 3. array( 'empty' => array( 'day' => 'DAY'. 'month' => 'MONTH'.x When passed to a select list. array( 'options' => array(1.. Output: <select name="data[Contact][date][day]" id="ContactDateDay"> <option value="">DAY</option> <option value="01">1</option> // .<select name="data[Contact][date][year]" id="ContactDateYear"> <option value="">YEAR</option> <option value="2036">2036</option> // . 'DMY'. 5). 'minute' => 'MINUTE'. <option value="1996">1996</option> More about Views 119 . 'empty' => '(choose one)' )).. 2.

only the tertiary colors would be passed. Release 2. Views . <option value="59">59</option> </select> <select name="data[Contact][date][meridian]" id="ContactDateMeridian"> <option value="am">am</option> <option value="pm">pm</option> </select> • $options[’hiddenField’] For certain input types (checkboxes. array('hiddenField' => false)). you should use this parameter on all inputs except the first. and the primary colors would be overridden: <h2>Primary Colors</h2> <input type="hidden" name="data[Color][Color]" id="Colors_" value="0" /> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsRed" /> <label for="ColorsRed">Red</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsBlue" /> <label for="ColorsBlue">Blue</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsYellow" /> <label for="ColorsYellow">Yellow</label> <h2>Tertiary Colors</h2> <input type="hidden" name="data[Color][Color]" id="Colors_" value="0" /> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsGreen" /> 120 Chapter 5. only the last group of input’s values will be saved In this example. If the hidden input is on the page in multiple places... Which outputs: <input type="checkbox" name="data[Post][Published]" value="1" id="PostPublished" /> If you want to create multiple blocks of inputs on a form that are all grouped together. <option value="12">12</option> </select>:<select name="data[Contact][date][min]" id="ContactDateMin"> <option value="">MINUTE</option> <option value="00">00</option> // .. radios) a hidden input is created so that the key in $this->request->data will exist even without a value specified: <input type="hidden" name="data[Post][Published]" id="PostPublished_" value="0" /> <input type="checkbox" name="data[Post][Published]" value="1" id="PostPublished" /> This can be disabled by setting the $options[’hiddenField’] = false: echo $this->Form->checkbox('published'..x </select> <select name="data[Contact][date][hour]" id="ContactDateHour"> <option value="">HOUR</option> <option value="01">1</option> // .CakePHP Cookbook Documentation.

4. array( 'type' => 'time'.CakePHP Cookbook Documentation. Ex: More about Views 121 . Form Element-Specific Methods All elements are created under a form for the User model as in the examples above. the HTML code generated will contain attributes that reference to the User model. You can set a different hidden field value other than 0 such as ‘N’: echo $this->Form->checkbox('published'. Defines the lower and/or upper end of values shown in the years select field. $options[’maxYear’] Used in combination with a date/datetime input. One for each 15 minutes. 'hiddenField' => 'N'. • $options[’orderYear’] Used in combination with a date/datetime input. • $options[’interval’] This option specifies the number of minutes between each option in the minutes select box: echo $this->Form->input('Model. Defines the order in which the year values will be set. For this reason. array( 'value' => 'Y'. Release 2. )).time'. The default value is ‘desc’. Would create 4 options in the minute select. 24. ‘M’ and ‘Y’ or null. • $options[’minYear’]. • $options[’round’] Can be set to up or down to force rounding in either direction. Defaults to null which rounds half up according to interval. Valid values include ‘asc’. The inputs will be put in the order defined by the dateFormat option. Valid values include any combination of ‘D’. ‘desc’. New in version 2. • $options[’dateFormat’] Used to specify the format of the select inputs for a date-related set of inputs. and null. Valid values include 12. Datetime options • $options[’timeFormat’] Used to specify the format of the select inputs for a time-related set of inputs.x <label for="ColorsGreen">Green</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsPurple" /> <label for="ColorsPurple">Purple</label> <input type="checkbox" name="data[Addon][Addon][]" value="5" id="ColorsOrange" /> <label for="ColorsOrange">Orange</label> Disabling the ’hiddenField’ on the second input group would prevent this behavior. 'interval' => 15 )).

'Your username'. Will output: <input name="data[User][username]" type="text" class="users" id="UserUsername" /> FormHelper::password(string $fieldName. Views . 'highlight'). or a string that will be used as a class name: echo $this->Form->label('User. echo $this->Form->label('User. $fieldName is used for generating the DOM id.name'. id=UserUsername FormHelper::label(string $fieldName.name'. Output: <label for="UserName" id="user-label">Name</label> <label for="UserName" class="highlight">Your username</label> FormHelper::text(string $name. Will output: <input name="data[User][id]" id="UserId" type="hidden" /> 122 Chapter 5. echo $this->Form->label('User. $options is used primarily to specify HTML tag attributes (such as the value or DOM id of an element in the form): echo $this->Form->text('username'.x name=data[User][username]. array $options) Creates a password field. Many of these methods also make use of a special $options parameter. string $text. 'Your username'). array $options) Create a label element.name'). array $options) The rest of the methods available in the FormHelper are for creating specific form elements. In this case. echo $this->Form->password('password'). Example: echo $this->Form->hidden('id'). array $options) Creates a hidden form input. Will output: <input name="data[User][password]" value="" id="UserPassword" type="password" /> FormHelper::hidden(string $fieldName.CakePHP Cookbook Documentation. however. array('class' => 'users')). $fieldName will be used to inflect the label’s text: echo $this->Form->label('User.name'. Release 2. array('id' => 'user-label')). If $text is undefined. Output: <label for="UserName">Name</label> <label for="UserName">Your username</label> $options can either be an array of HTML attributes. null.

the value corresponding to id field will automatically be added to the HTML generated.CakePHP Cookbook Documentation. $options[’cols’] These two keys specify the number of rows and columns: echo $this->Form->textarea( 'textarea'. Output: <textarea name="data[Form][textarea]" cols="5" rows="5" id="FormTextarea"> </textarea> More about Views 123 . This means that if there are validation errors on hidden fields. 'escape' => false) ).x If the form is edited (that is. the value corresponding to notes field will automatically be added to the HTML generated. Will output: <textarea name="data[User][notes]" id="UserNotes"></textarea> If the form is edited (that is. Defaults to true. textarea() supports a few specific options: •$options[’rows’]..0: Hidden fields no longer remove the class attribute. the array $this->request->data will contain the information saved for the User model). Options In addition to the Common options. array('rows' => '5'.. 'cols' => '5') ). echo $this->Form->input( 'notes'. </textarea> Note: The textarea input type allows for the $options attribute of ’escape’ which determines whether or not the contents of the textarea should be escaped. FormHelper::textarea(string $fieldName. Example: <textarea name="data[User][notes]" id="UserNotes"> This text is to be edited. // OR. echo $this->Form->textarea('notes'.. echo $this->Form->textarea('notes'). array $options) Creates a textarea input field. Release 2. the error-field class name will be applied. array('escape' => false). array('type' => 'textarea'. the array $this->request->data will contain the information saved for the User model). Example for data[User][id] = 10: <input name="data[User][id]" id="UserId" type="hidden" value="10" /> Changed in version 2.

$options. Set $attributes[’legend’] to false to remove them. 'F' => 'Female').g. •$attributes[’separator’] to specify HTML in between radio buttons (e. •$attributes[’between’] specify some content to be inserted between the legend and first element. array $options. Will output: <input type="hidden" name="data[User][done]" value="0" id="UserDone_" /> <input type="checkbox" name="data[User][done]" value="555" id="UserDone" /> If you don’t want the Form helper to create a hidden input: echo $this->Form->checkbox('done'. •$attributes[’legend’] Radio elements are wrapped with a legend and fieldset by default. $attributes = array('legend' => false). echo $this->Form->radio('gender'. array('hiddenField' => false)). Views . <br />). $options = array('M' => 'Male'. •$attributes[’disabled’] Setting this to true or ’disabled’ will disable all of the generated radio buttons.CakePHP Cookbook Documentation. Will output: <input name="data[User][gender]" id="UserGender_" value="" type="hidden" /> <input name="data[User][gender]" id="UserGenderM" value="M" type="radio" /> 124 Chapter 5. array $attributes) Creates a set of radio button inputs. $attributes). This method also generates an associated hidden form input to force the submission of data for the specified field. Will output: <input type="hidden" name="data[User][done]" value="0" id="UserDone_" /> <input type="checkbox" name="data[User][done]" value="1" id="UserDone" /> It is possible to specify the value of the checkbox by using the $options array: echo $this->Form->checkbox('done'. Release 2. array('value' => 555)). Options •$attributes[’value’] to set which value should be selected default.x FormHelper::checkbox(string $fieldName. array $options) Creates a checkbox form element. Will output: <input type="checkbox" name="data[User][done]" value="1" id="UserDone" /> FormHelper::radio(string $fieldName. echo $this->Form->checkbox('done').

Release 2. with the option specified by $attributes[’value’] shown as selected by default. $options. echo $this->Form->select('gender'.3. populated with the items in $options. More about Views 125 . FormHelper::select(string $fieldName. Unless the ‘type’ is specified as ‘radio’. 'F' => 'Female').x <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. Changed in version 2. •$attributes[’options’] This key allows you to manually specify options for a select input. 'F' => 'Female'). setting $attributes[’value’] to a selected value or boolean false will do just that. array( 'Value 1' => 'Label 1'.4. Set the ‘empty’ key in the $attributes variable to false to turn off the default empty option: $options = array('M' => 'Male'.CakePHP Cookbook Documentation. 'Value 2' => 'Label 2'. Output: <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> Options can also be supplied as key-value pairs: echo $this->Form->select('field'. array $attributes) Creates a select element. or for a radio group. echo $this->Form->select('gender'. $options). the FormHelper will assume that the target output is a select input: echo $this->Form->select('field'. Defaults to true: $options = array('M' => 'Male'. Will output: <select name="data[User][gender]" id="UserGender"> <option value=""></option> <option value="M">Male</option> <option value="F">Female</option> </select> The select input type allows for a special $option attribute called ’escape’ which accepts a bool and determines whether to HTML entity encode the contents of the select options. array(1. array $options.5)).1.1: The $attributes[’disabled’] option was added in 2. array('escape' => false)).2.

array('multiple' => true) ).field'. This works on multiple checkboxes and radio buttons too. 'Group 2' => array( 'Value 3' => 'Label 3' ) ). echo $this->Form->select('field'. $options). 'Value 2' => 'Label 2' ). Views . Output: <select name="data[User][field]" id="UserField"> <optgroup label="Group 1"> <option value="Value 1">Label 1</option> <option value="Value 2">Label 2</option> </optgroup> <optgroup label="Group 2"> <option value="Value 3">Label 3</option> </optgroup> </select> •$attributes[’multiple’] If ‘multiple’ has been set to true for an input that outputs a select. just pass data in hierarchical format. but instead of optgroups wraps elements in fieldsets: $options = array( 'Group 1' => array( 'Value 1' => 'Label 1'. the select will allow multiple selections: echo $this->Form->select( 'Model.CakePHP Cookbook Documentation.field'. echo $this->Form->select('Model. Output: <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> If you would like to generate a select with optgroups. $options. Release 2. 'Value 2' => 'Label 2' ).x 'Value 3' => 'Label 3' )). $options. Alternatively set ‘multiple’ to ‘checkbox’ to output a list of related check boxes: $options = array( 'Value 1' => 'Label 1'. array( 126 Chapter 5.

Output: <div class="input select"> <label for="ModelField">Field</label> <input name="data[Model][field]" value="" id="ModelField" type="hidden"> <div class="checkbox"> <input name="data[Model][field][]" value="Value 1" id="ModelField1" type="checkbox"> <label for="ModelField1">Label 1</label> </div> <div class="checkbox"> <input name="data[Model][field][]" value="Value 2" id="ModelField2" type="checkbox"> <label for="ModelField2">Label 2</label> </div> </div> •$attributes[’disabled’] When creating checkboxes. FormHelper::file(string $fieldName. 'Value 2' => 'Label 2' ). array $options) More about Views 127 .CakePHP Cookbook Documentation. echo $this->Form->select('Model.x 'multiple' => 'checkbox' )). $options. 'disabled' => array('Value 1') )). Output: <div class="input select"> <label for="ModelField">Field</label> <input name="data[Model][field]" value="" id="ModelField" type="hidden"> <div class="checkbox"> <input name="data[Model][field][]" disabled="disabled" value="Value 1" id="ModelField1" type="checkbox"> <label for="ModelField1">Label 1</label> </div> <div class="checkbox"> <input name="data[Model][field][]" value="Value 2" id="ModelField2" type="checkbox"> <label for="ModelField2">Label 2</label> </div> </div> Changed in version 2. To disable all checkboxes set disabled to true: $options = array( 'Value 1' => 'Label 1'.3. this option can be set to disable all or some checkboxes.3: Support for arrays in $attributes[’disabled’] was added in 2. array( 'multiple' => 'checkbox'. Release 2.field'.

Validating Uploads Below is an example validation method you could define in your model to validate whether a file has been successfully uploaded: public function isUploadedFile($params) { $val = array_shift($params). Due to the limitations of HTML itself. 'size' => 41737. file fields provide an expanded data array to the script receiving the form data.CakePHP Cookbook Documentation. array('type' => 'file')). 'type' => 'file' )).submittedfile').tmp'.pdf'. ‘tmp_name’ will have a different path in a Unix environment: $this->request->data['Document']['submittedfile'] = array( 'name' => 'conference_schedule.x To add a file upload field to a form. Each time the form is displayed. // OR echo $this->Form->file('Document. array( 'enctype' => 'multipart/form-data' )). ). 'type' => 'application/pdf'. For the example above. Release 2. so start off with a create function such as the following: echo $this->Form->create('Document'. } 2 http://php. 'error' => 0. Next add either of the two lines to your form view file: echo $this->Form->input('Document. // OR echo $this->Form->create('Document'. array( 'between' => '<br />'.net/features. This array is generated by PHP itself. if the CakePHP was installed on a Windows server. if ((isset($val['error']) && $val['error'] == 0) || (!empty( $val['tmp_name']) && $val['tmp_name'] != 'none') ) { return is_uploaded_file($val['tmp_name']). Upon submission. } return false. so for more detail on the way PHP handles data passed via file fields read the PHP manual section on file uploads2 . Views .file-upload 128 Chapter 5. the value inside will be empty.submittedfile'. it is not possible to put default values into input fields of type ‘file’. the values in the submitted data array would be organized as follows. 'tmp_name' => 'C:/WINDOWS/TEMP/php1EE. you must first make sure that the form enctype is set to “multipart/form-data”.

It is enclosed between div tags by default.png"></div> FormHelper::button(string $title. array('type' => 'reset')). remember to set the form encoding-type. Will output: <div class="submit"><input type="image" src="/img/ok. 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. array('type' => 'file')). array $options = array()) Creates an HTML button with the specified title and a default type of “button”. echo $this->Form->file('avatar'). $this->Form->button('Submit Form'. 3. array('type' => 'button')).png'). If the supplied $caption is a URL to an image (it contains a ‘. Release 2. echo echo echo echo $this->Form->button('A Button'). Will output: <form enctype="multipart/form-data" method="post" action="/users/add"> <input name="data[User][avatar]" value="" id="UserAvatar" type="file"> Note: When using $this->Form->file().(the default). $this->Form->button('Another Button'. array('type' => 'submit')).button: Creates a standard push button. array $options) Creates a submit button with caption $caption.submit: Same as the $this->Form->submit method . by setting the type option to ‘file’ in $this->Form->create() Creating buttons and submit elements FormHelper::submit(string $caption. $options[’type’] will output one of the three possible button types: Setting 1. you can avoid this by declaring $options[’div’] = false: echo $this->Form->submit(). echo $this->Form->submit('ok.CakePHP Cookbook Documentation. Will output: More about Views 129 .x Creates a file input: echo $this->Form->create('User'. $this->Form->button('Reset the Form'. 2. the submit button will be rendered as an image.’ character).reset: Creates a form reset button.

It will also pre-select the fields with the current datetime. array $options = array ()) Creates an HTML link. If all you are looking for is a button to submit your form. but access the URL using method POST. mixed $url. int $maxYear.6: The argument $confirmMessage was deprecated. Requires JavaScript to be enabled in browser. They allow buffering the generated form tag. $dateFormat = ‘DMY’. $attributes = array()) Creates a set of select inputs for date and time. int $minYear. This helps avoiding nested form tags. Creating date and time inputs FormHelper::dateTime($fieldName. ‘MDY’. 'escape' => true )). Release 2. This method creates a <form> element. array( 'type' => 'submit'. FormHelper::postButton(string $title. $timeFormat = ‘12’. If you want to use this method inside of an existing form. and null. mixed $url = null. This method creates a <form> element. Instead use FormHelper::submit() or FormHelper::button() to create buttons inside opened forms. array $attributes) Creates a select element populated with the years from $minYear to $maxYear. Valid values for $timeFormat are ‘12’. Setting ’inline’ => false will add the form tag to the postLink content block. you must use the inline or block options so that the new form can be rendered outside of its parent. Changed in version 2. ‘24’. You can specify not to display empty values by setting “array(‘empty’ => false)” in the attributes parameter. Views . Defaults to false: echo $this->Form->button('Submit Form'. if you want to use a custom block you can specify it using the block option instead. So do not use this method in some opened form. instead of returning with the link. Use confirm key in $options instead. array $options = array ()) Create a <button> tag with a surrounding <form> that submits via POST. Changed in version 2. then you should use FormHelper::submit() instead.CakePHP Cookbook Documentation.3: The method option was added. FormHelper::postLink(string $title.x <button <button <button <button type="submit">A Button</button> type="button">Another Button</button> type="reset">Reset the Form</button> type="submit">Submit Form</button> The button input type supports the escape option. ‘YMD’ or ‘NONE’. Valid values for $dateformat are ‘DMY’. FormHelper::year(string $fieldName.5: The inline and block options were added. HTML attributes 130 Chapter 5. Changed in version 2. which accepts a bool and determines whether to HTML entity encode the $title of the button.

To create an empty option with prompt text of your choosing (e. FormHelper::day(string $fieldName. array('monthNames' => false)).x may be supplied in $attributes. (Note: the default months are internationalized and can be translated using localization. array $attributes) Creates a select element populated with month names: echo $this->Form->month('mob'). or have months displayed as numbers by passing false. 2000.CakePHP Cookbook Documentation. the first option is ‘Day’). Release 2. the select will not include an empty option: echo $this->Form->year('purchased'. you can supply the text as the final parameter as follows: More about Views 131 . array $attributes) Creates a select element populated with the (numerical) days of the month. If $attributes[’empty’] is false. 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. 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> <option value="2004">2004</option> <option value="2003">2003</option> <option value="2002">2002</option> <option value="2001">2001</option> <option value="2000">2000</option> </select> FormHelper::month(string $fieldName. date('Y')).g.): echo $this->Form->month('mob'.

x echo $this->Form->day('created'). 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> . Displaying and checking errors FormHelper::error(string $fieldName. array $options) Shows a validation error message.. array $attributes) Creates a select element populated with ‘am’ and ‘pm’. 132 Chapter 5. If a string. specified by $text.CakePHP Cookbook Documentation. array $attributes) Creates a select element populated with the minutes of the hour. FormHelper::tagIsInvalid() Returns false if given form field described by the current entity has no errors. Otherwise it returns the validation message. Views . } Note: When using FormHelper::input(). for the given field. in the event that a validation error has occurred. errors are rendered by default. if ($this->Form->isFieldError('gender')) { echo $this->Form->error('gender'). FormHelper::meridian(string $fieldName. array $attributes) Creates a select element populated with the hours of the day. Release 2. •‘wrap’ mixed Whether or not the error message should be wrapped in a div. mixed $text. •‘class’ string The class name for the error message FormHelper::isFieldError(string $fieldName) Returns true if the supplied $fieldName has an active validation error. Options: •‘escape’ bool Whether or not to HTML escape the contents of the error. boolean $format24Hours. will be used as the HTML tag to use.. FormHelper::minute(string $fieldName. <option value="31">31</option> </select> FormHelper::hour(string $fieldName.

You can declare a set of default options for input() using FormHelper::inputDefaults(). Working with SecurityComponent SecurityComponent offers several features that make your forms safer and more secure. The effected methods are: More about Views 133 . FormHelper::secure(array $fields = array()) Generates a hidden field with a security hash based on the fields used in the form. no label with class 'fancy' // has a label element same defaults echo $this->Form->input( 'username'. and reduces the duplication that $selected created. By simply including the SecurityComponent in your controller.0 updates $selected parameter removed The $selected parameter was removed from several methods in FormHelper. FormHelper::unlockField($name) Unlocks a field making it exempt from the SecurityComponent field hashing.CakePHP Cookbook Documentation. As mentioned previously when using SecurityComponent. Changing the default options allows you to consolidate repeated options into a single method call: $this->Form->inputDefaults(array( 'label' => false. you’ll automatically benefit from CSRF and form tampering features. // No div. All methods now support a $attributes[’value’] key now which should be used in place of $selected. 'class' => 'fancy' ) ). 'div' => false. The $name parameter should be the entity name for the input: $this->Form->unlockField('User. array('label' => 'Username') ). 2.x Setting Defaults for all fields New in version 2. reducing the number of arguments.2.id'). You can override the default options by declaring the option in the input() call: echo $this->Form->input('password'). This also allows the fields to be manipulated by JavaScript. Release 2. This change simplifies the FormHelper methods. you should always close your forms using FormHelper::end(). This will ensure that the special _Token inputs are generated. All inputs created from that point forward will inherit the options declared in inputDefaults.

'value' => 'bar') Note: The HtmlHelper is available in all views by default. it’s usually due to its name being missing from a manually configured $helpers controller variable. named. Release 2.x • FormHelper::select() • FormHelper::dateTime() • FormHelper::year() • FormHelper::month() • FormHelper::day() • FormHelper::hour() • FormHelper::minute() • FormHelper::meridian() Default URLs on forms is the current action The default URL for all forms. Don’t be afraid to use it often . is now the current URL including passed. If you’re getting an error informing you that it isn’t there. the error-field class name will be applied.CakePHP Cookbook Documentation.you can cache views in CakePHP in order to save some CPU cycles when views are being 134 Chapter 5. You can override this default by supplying $options[’url’] in the second parameter of $this->Form->create() FormHelper::hidden() Hidden fields no longer remove the class attribute. Here are a few examples of how to use the $options parameter: Desired attributes: <tag class="someClass" /> Array parameter: array('class' => 'someClass') Desired attributes: <tag name="foo" value="bar" /> Array parameter: array('name' => 'foo'. Using this helper will enable your application to be more light on its feet. Inserting Well-Formatted elements The most important task the HtmlHelper accomplishes is creating well formed markup. and more resilient to change. Many HtmlHelper methods include a $options parameter. HtmlHelper class HtmlHelper(View $view. faster. that allow you to tack on any extra attributes on your tags. and querystring parameters. array $settings = array()) The role of the HtmlHelper in CakePHP is to make HTML-related options easier. Views . and more flexible on where it is placed in relation to the root of a domain. This means that if there are validation errors on hidden fields.

Parameters • $path (mixed) – Either a string of the CSS file to link. More about Views 135 . echo $this->Html->css('forms').encoding will be used. Creates a link(s) to a CSS style-sheet.css" /> The first parameter can be an array to include multiple files. charset=utf-8" /> Alternatively. the link tags are added to the css block which you can print inside the head tag of the document. If null. the value of App.CakePHP Cookbook Documentation. You can use the block option to control which block the link element will be appended to.4.x rendered and delivered. HtmlHelper::charset($charset=null) Parameters • $charset (string) – Desired character set. charset=ISO-8859-1" /> HtmlHelper::css(mixed $path. Will output: <meta http-equiv="Content-Type" content="text/html. Used to create a meta tag specifying the document’s character. This section will cover some of the methods of the HtmlHelper and how to use them. By default it will append to the css block. This method of CSS inclusion assumes that the CSS file specified resides inside the /app/webroot/css directory if path doesn’t start with a ‘/’. Will output: <link rel="stylesheet" type="text/css" href="/css/forms. Release 2. or an array with multiple files • $options (array) – An array of options or html attributes. If key ‘rel’ in $options array is set to ‘import’ the stylesheet will be imported. Will output: <meta http-equiv="Content-Type" content="text/html. array $options = array()) Changed in version 2. If key ‘inline’ is set to false in $options parameter. echo $this->Html->charset('ISO-8859-1'). Defaults to UTF-8 Example use: echo $this->Html->charset().

ico'.css'). • $options (array) – An array of html attributes. you would: Changed in version 2. Support for plugin syntax was added.x echo $this->Html->css(array('forms'.ico" type="image/x-icon" 136 Chapter 5.CakePHP Cookbook Documentation. This method is handy for linking to external resources like RSS/Atom feeds and favicons.css'. Like css().css" /> You can include CSS files from any loaded plugin using plugin syntax.css" /> <link rel="stylesheet" type="text/css" href="/css/tables.toolbar.ico" title="favicon.common. 'tables'. '/favicon.4. echo $this->Html->css('Blog. Will output: <link rel="stylesheet" type="text/css" href="/css/forms. Changed in version 2.css. array('type' => 'icon') ).css you could use the following: echo $this->Html->css('DebugKit.ico'. Release 2. string $url = null. array $options = array()) Parameters • $type (string) – The type meta tag you want. Views .1: The block option was added. 'menu')). If you set the “type” attribute using the $options parameter. ie .array(’inline’ => false). To include app/Plugin/DebugKit/webroot/css/toolbar. HtmlHelper::meta(string $type. ?> // Output (line breaks added) <link href="http://example.common. array('plugin' => false)).css" /> <link rel="stylesheet" type="text/css" href="/css/menu. For example if you had a Blog plugin. and also wanted to include app/webroot/css/Blog. CakePHP contains a few shortcuts: type html rss atom icon translated value text/html application/rss+xml application/atom+xml image/x-icon <?php echo $this->Html->meta( 'favicon. you can specify whether or not you’d like this tag to appear inline or appended to the meta block by setting the ‘inline’ key in the $options parameter to false. • $url (mixed) – The URL for the meta tag. either a string or a routing array.com/favicon. If you want to include a CSS file which shares a name with a loaded plugin you can do the following.

?> // Output <meta name="keywords" content="enter any meta keyword here" /> <?php echo $this->Html->meta( 'description'. HtmlHelper::docType(string $type = ‘xhtml-strict’) Parameters • $type (string) – The type of doctype being made. To output a robots noindex tag use the following code: echo $this->Html->meta(array('name' => 'robots'.1: The block option was added. 'content' => 'noindex')). ?> // 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.CakePHP Cookbook Documentation. 'enter any meta description here' ). '/comments/index.rss" title="Comments" type="application/rss+xml" rel="alternate" /> This method can also be used to add the meta keywords and descriptions.x rel="alternate" /> <?php echo $this->Html->meta( 'Comments'. Example: <?php echo $this->Html->meta( 'keywords'. Returns a (X)HTML doctype tag. Supply the doctype according to the following table: More about Views 137 . Changed in version 2. Release 2. array('type' => 'rss') ). 'enter any meta keyword here' ).rss'.com/comments/index. ?> // Output (line breaks added) <link href="http://example.

Will output: background:#633. HtmlHelper::image(string $path.1 echo $this->Html->docType().1: The default doctype is html5 in 2. padding:10px. // Outputs: // <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4. echo $this->Html->style(array( 'background' => '#633'. • $oneline (boolean) – Should the contents be on one line.w3. HtmlHelper::style(array $data. // Outputs: // <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. 'border-bottom' => '1px solid #000'. Creates a formatted image tag. Views .dtd"> echo $this->Html->docType('html5'). Especially handy if your CSS file is dynamic. boolean $oneline = true) Parameters • $data (array) – A set of key => values with CSS properties.1. border-bottom:1px solid #000. 138 Chapter 5.0 Strict//EN" // "http://www.CakePHP Cookbook Documentation. // Outputs: <!DOCTYPE html> echo $this->Html->docType('html4-trans').org/TR/xhtml1/DTD/xhtml1-strict.x type html4-strict html4-trans html4-frame html5 xhtml-strict xhtml-trans xhtml-frame xhtml11 translated value HTML4 Strict HTML4 Transitional HTML4 Frameset HTML5 XHTML1 Strict XHTML1 Transitional XHTML1 Frameset XHTML1. 'padding' => '10px' )).01 Transitional//EN" // "http://www.dtd"> Changed in version 2. • $options (array) – An array of html attributes. The path supplied should be relative to /app/webroot/img/.w3. Release 2.org/TR/html4/loose. array $options = array()) Parameters • $path (string) – Path to the image. Builds CSS style definitions based on the keys and values of the array passed to the method.

and also wanted to include app/webroot/img/Blog. you would: echo $this->Html->image('Blog. mixed $url = null. For example if you had a Blog plugin.icon.1: The fullBase option was added.jpg" alt="" /> You can include image files from any loaded plugin using plugin syntax.png" alt="CakePHP" /> To create an image link specify the link destination using the url option in $options.png".jpg".icon. If you want to include an image file which shares a name with a loaded plugin you can do the following. Will output: <img src="http://example. To include app/Plugin/DebugKit/webroot/img/icon. More about Views 139 . General purpose method for creating HTML links.png'.icon. or want absolute paths to images you can use the fullBase option: echo $this->Html->image("logo. Support for plugin syntax was added.png. array('alt' => 'CakePHP')).com/img/logo.png You could use the following: echo $this->Html->image('DebugKit. or a routing array. 6) )). HtmlHelper::link(string $title. array('fullBase' => true)). Will output: <img src="/img/cake_logo. array( "alt" => "Brownies".x echo $this->Html->image('cake_logo. • $options (array) – An array of html attributes. Release 2.png'. echo $this->Html->image("recipes/6. • $url (mixed) – Either the string location.CakePHP Cookbook Documentation.png').jpg" alt="Brownies" /> </a> If you are creating images in emails. Use $options to specify attributes for the element and whether or not the $title should be escaped. 'url' => array('controller' => 'recipes'. Will output: <a href="/recipes/view/6"> <img src="/img/recipes/6. array('plugin' => false)). array $options = array()) Parameters • $title (string) – The text to display as the body of the link. Changed in version 2. 'action' => 'view'.

'action' => 'view'. 'target' => '_blank') ). 'width' => 500)) ). echo $this->Html->link('View image'.CakePHP Cookbook Documentation. array('controller' => 'recipes'. array('class' => 'button'. array('confirm' => 'Are you sure you wish to delete this recipe?') ). Will output: <a href="/pages/home" class="button" target="_blank">Enter</a> Use ’full_base’ => true option for absolute URLs: echo $this->Html->link( 'Dashboard'.yourdomain. 1. '?' => array('height' => 400. '/pages/home'. Will output: <a href="/recipes/delete/6" onclick="return confirm( 'Are you sure you wish to delete this recipe?' ). 'full_base' => true ) ). Will output: <a href="http://www.x echo $this->Html->link( 'Enter'. array( 'controller' => 'images'."> Delete </a> Query strings can also be created with link(). array( 'controller' => 'dashboards'. 'action' => 'index'. Views . 6). Release 2. Will output: 140 Chapter 5. 'action' => 'delete'.com/dashboards/index">Dashboard</a> Specify confirm key in $options to display a JavaScript confirm() dialog: echo $this->Html->link( 'Delete'.

x <a href="/images/view/1?height=400&width=500">View image</a> When using named parameters. Will output: <a href="/recipes/view/6" title="hi &quot.howdy&quot. array('escapeTitle' => false. array("alt" => "Brownies")). 'comments' => false ) ). Release 2. set the escape option to false in the $options array. Will output: <a href="/recipes/view/id:6/comments:false"> <img src="/img/recipes/6.CakePHP Cookbook Documentation. <?php echo $this->Html->link( $this->Html->image("recipes/6. array( 'controller' => 'recipes'.jpg" alt="Brownies" /> </a> HTML special characters in $title will be converted to HTML entities. 'action' => 'view'.jpg". Will output: <a href="/recipes/view/6"> <img src="/img/recipes/6. <?php echo $this->Html->link( $this->Html->image("recipes/6. array("alt" => "Brownies")).4 you can use the option escapeTitle to disable just escaping of title and not the attributes. As of 2. “recipes/view/6/comments:false”) will result in the colon characters being HTML escaped and the link will not work as desired.jpg" alt="Brownies" /> </a> More about Views 141 . array('escape' => false) ). use the array syntax and include names for ALL parameters in the URL. "recipes/view/6".jpg" alt="Brownies" /> </a> Setting escape to false will also disable escaping of attributes of the link."> <img src="/img/recipes/6.jpg'.jpg". 'id' => 6. Using the string syntax for paramters (i. To disable this conversion. <?php echo $this->Html->link( $this->Html->image('recipes/6. 'recipes/view/6'. array('alt' => 'Brownies')).e. 'title' => 'hi "howdy"') ).

and special options.mp4'. If type is not provided media type is guessed based on file’s mime type. Changed in version 2.x Changed in version 2. valid values are “audio” or “video”. ?> 142 Chapter 5. HtmlHelper::media(string|array $path. 'text' => 'Fallback text' )).4: The escapeTitle option was added. codecs='theora. 'type' => "video/ogg. ?> // Output <audio src="/files/audio. array( 'fullBase' => true. array( 'src' => 'video. ?> // Output <video src="http://www.mp3'). vorbis'" ) ). Returns a formatted audio/video tag: <?php echo $this->Html->media('audio.mp3"></audio> <?php echo $this->Html->media('video.6: The argument $confirmMessage was deprecated. array $options) Parameters • $path (string|array) – Path to the media file. Release 2. – text Text to include inside the audio/video tag – pathPrefix Path prefix to use for relative URLs. relative to the webroot/{$options[’pathPrefix’]} directory.com/files/video.mp4'. Views .1.CakePHP Cookbook Documentation. Also check HtmlHelper::url method for more examples of different types of URLs. • $options (array) – Array of HTML attributes.ogg'. defaults to ‘files/’ – fullBase If set to true. the src attribute will get a full address including domain name New in version 2. array('autoplay') ). Use confirm key in $options instead. Or an array where each item itself can be a path string or an associate array containing keys src and type.mp4">Fallback text</video> <?php echo $this->Html->media( array( 'video.somehost. Options: – type Type of media element to generate.

• $options (array) – An array of html attributes.: <?php echo $this->Html->tag('span'. array $options) Parameters • $class (string) – The class name for the div. Returns text wrapped in a specified tag. • $options (array) – An array of html attributes. and the second is used to supply the text to be wrapped by div tags. The first parameter specifies a CSS class.mp4" type="video/mp4"/> <source src="/files/video. • $text (string) – The content inside the div. string $text.ogg" type="video/ogg. Used for creating div-wrapped sections of markup. null. only an opening div tag is returned.CakePHP Cookbook Documentation.: More about Views 143 . vorbis'"/> </video> HtmlHelper::tag(string $tag.x // Output <video autoplay="autoplay"> <source src="/files/video. • $text (string) – The contents for the tag. string $text. 'Hello World. <?php echo $this->Html->tag('span'.'. $text will be printed HTML-escaped. array('class' => 'welcome')). This replaces a fourth parameter boolean $escape = false that was available in previous versions. array $options) Parameters • $tag (string) – The tag name being generated. array('class' => 'welcome')). ?> // Output <span class="welcome">Hello World</span> // No text specified. Release 2. If no text is specified. HtmlHelper::div(string $class. codecs='theora. If no text is specified then only the opening <tag> is returned. ?> // Output <span class="welcome"> Note: Text is not escaped by default but you may use $options[’escape’] = true to escape your text. If the ‘escape’ key has been set to true in the last parameter.

By default.CakePHP Cookbook Documentation. $options[’once’] controls whether or not you want to include this script once per request or more than once. ?> // Output <p>Hello World.'). the attributes will be applied to all of the generated script tags. the script tags will instead be added to the script block which you can print elsewhere in the document. If you override this by setting $options[’inline’] to false. contained either locally or as a remote URL. or an array of strings for multiple files. • $options (array) – An array of html attributes.'). If an array of script tags is used. only a starting <p> tag is returned.</div> HtmlHelper::para(string $class. 'Please enter your credit card number. string $text. If you wish to override which block name is used. Views . array $options) Parameters • $class (string) – The class name for the paragraph. script tags are added to the document inline.x <?php echo $this->Html->div('error'. • $text (string) – The content inside the paragraph.: <?php echo $this->Html->para(null. ?> // Output <div class="error">Please enter your credit card number. you can do so by setting $options[’block’]. mixed $options) Parameters • $url (mixed) – Either a string to a single JavaScript file. Will output: 144 Chapter 5. Include a script file(s). This method of JavaScript file inclusion assumes that the JavaScript file specified resides inside the /app/webroot/js directory: echo $this->Html->script('scripts'). 'Hello World. • $options (array) – An array of html attributes. This defaults to true. If no text is supplied. Release 2. You can use $options to set additional properties to the generated script tag. Returns a text wrapped in a CSS-classed <p> tag.</p> HtmlHelper::script(mixed $url.

Release 2.CakePHP Cookbook Documentation. To include app/Plugin/DebugKit/webroot/js/toolbar.js"></script> You can append the script tag to a specific block using the block option: echo $this->Html->script('wysiwyg'. Set $options[’inline’] to false to have the script block appear in the script view block. Will output: <script type="text/javascript" href="http://code. you would: echo $this->Html->script('Blog.jquery.min. If you want to include a script file which shares a name with a loaded plugin you can do the following. • $options (array) – An array of html attributes. You can include script files from any loaded plugin using plugin syntax. Will output: <script type="text/javascript" href="/js/jquery. You can also link to a remote URL: echo $this->Html->script('http://code. echo $this->Html->script(array('jquery'. array('block' => 'scriptBottom')). HtmlHelper::scriptBlock($code. and also wanted to include app/webroot/js/Blog.com/jquery.js"></script> <script type="text/javascript" href="/js/scripts. 'wysiwyg'. $options = array()) Parameters • $code (string) – The code to go in the script tag. Generate a code block containing $code.plugins.toolbar.x <script type="text/javascript" href="/js/scripts.js"></script> You can link to files with absolute paths as well to link files that are not in app/webroot/js: echo $this->Html->script('/otherdir/script_file').js'.com/jquery.js"> </script> The first parameter can be an array to include multiple files. array('plugin' => false)). In your layout you can output all the script tags added to ‘scriptBottom’: echo $this->fetch('scriptBottom').plugins.js'). 'scripts')). Changed in version 2. Support for plugin syntax was added. Other options defined will be added as attributes More about Views 145 .jquery. For example if you had a Blog plugin.js.min.1: The block option was added.js you could use the following: echo $this->Html->script('DebugKit.js').js"></script> <script type="text/javascript" href="/js/wysiwyg.

Views . array $options = array(). 'Spanish'. HtmlHelper::nestedList(array $list. returns the generated script element or null if the script block was opened with inline = false. echo $this->Html->nestedList($list). ) ). Options are the same as scriptBlock() HtmlHelper::scriptEnd() End a buffering script block. Begin a buffering code block. string $tag = ‘ul’) Parameters • $list (array) – Set of elements to list. 'British'. ). • $options (array) – Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag. Output: // Output (minus the whitespace) <ul> 146 Chapter 5. $this->Html->scriptBlock(’stuff’. will create a script tag with defer="defer" attribute. echo $this->Js->alert('I am in the javascript'). $this->Html->scriptEnd().CakePHP Cookbook Documentation. • $itemOptions (array) – Additional HTML attributes of the list item (LI) tag. An example of using scriptStart() and scriptEnd() would be: $this->Html->scriptStart(array('inline' => false)). Release 2. Build a nested list (UL/OL) out of an associative array: $list = array( 'Languages' => array( 'English' => array( 'American'. array $itemOptions = array(). • $tag (string) – Type of list tag to use (ol/ul). This code block will capture all output between scriptStart() and scriptEnd() and create an script tag. HtmlHelper::scriptStart($options = array()) Parameters • $options (array) – An array of html attributes to be used when scriptEnd is called. 'Canadian'. 'German'.x to script tags. array(’defer’ => true)).

see below. Output: <tr> <th>Date</th> <th>Title</th> <th>Active</th> </tr> echo $this->Html->tableHeaders( array('Date'. As of 2. Output: <tr class="status"> <th class="product_table">Date</th> <th class="product_table">Title</th> <th class="product_table">Active</th> </tr> Changed in version 2. 'Active')).x <li>Languages <ul> <li>English <ul> <li>American</li> <li>Canadian</li> <li>British</li> </ul> </li> <li>Spanish</li> <li>German</li> </ul> </li> </ul> HtmlHelper::tableHeaders(array $names.2 you can set attributes per column. array('class' => 'product_table') ). these are used instead of the defaults provided in the $thOptions: More about Views 147 . array $thOptions = null) Parameters • $names (array) – An array of strings to create table headings.'Active'). 'Title'.2: tableHeaders() now accepts attributes per cell. array $trOptions = null. Release 2. • $trOptions (array) – An array of html attributes for the <tr> • $thOptions (array) – An array of html attributes for the <th> elements Creates a row of table header cells to be placed inside of <table> tags. echo $this->Html->tableHeaders(array('Date'. array('class' => 'status').CakePHP Cookbook Documentation.'Title'.

2006'. 2006'. 2007'. array( 'Aug 1st. 'Yes'). so that the odd/even count is reset to zero just for that call. 2007</td><td>Best Brownies</td><td>Yes</td></tr> <tr><td>Jun 21st. 2007'. array $oddTrOptions = null. array('Name' => array('class' => 'highlight')).x echo $this->Html->tableHeaders(array( 'id'. 'Best Brownies'. Wrap a single table cell within an array() for specific <td>-attributes. Release 2. Output: <tr><td>Jul 7th. 'Smart Cookies'. 2007'. 'Yes'). array('Jun 21st. $useCount = false. Creates table cells. array( 'Best Brownies'. will use a non-static $count variable. • $continueOddEven (boolean) – If false. 'Yes'). assigning <tr> attributes differently for odd. 2006</td><td>Anti-Java Cake</td><td>No</td></tr> echo $this->Html->tableCells(array( array( 'Jul 7th. • $evenTrOptions (array) – An array of html attributes for the even <tr>’s. )). array('Date' => array('class' => 'sortable')) )). array('Aug 1st. 'No'). Views . 148 Chapter 5. array $evenTrOptions = null. • $oddTrOptions (array) – An array of html attributes for the odd <tr>’s. 'Smart Cookies'.and even-numbered rows. $continueOddEven = true) Parameters • $data (array) – A two dimensional array with data for the rows. in rows. 'Yes').CakePHP Cookbook Documentation. • $useCount (boolean) – Adds class “column-$i”. array('class' => 'highlight') ). array('Jun 21st. echo $this->Html->tableCells(array( array('Jul 7th. 2007'. 'Anti-Java Cake'. Output: <tr> <th>id</th> <th class="highlight">Name</th> <th class="sortable">Date</th> </tr> HtmlHelper::tableCells(array $data. 2007</td><td>Smart Cookies</td><td>Yes</td></tr> <tr><td>Aug 1st.

)). array('Orange'. 'Orange'). 'Banana'). Output: <tr> <td> Jul 7th. array('id' => 'special')) ). 'Apple'). array('No'. 2007 </td> <td class="highlight"> Best Brownies </td> <td> Yes </td> </tr> <tr> <td> Jun 21st. Output: More about Views 149 . Release 2. 2006 </td> <td> Anti-Java Cake </td> <td id="special"> No </td> </tr> echo $this->Html->tableCells( array( array('Red'. array('Yellow'.x 'Anti-Java Cake'. ).CakePHP Cookbook Documentation. 2007 </td> <td> Smart Cookies </td> <td> Yes </td> </tr> <tr> <td> Aug 1st. array('class' => 'darker') ).

If $url is empty.x <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> HtmlHelper::url(mixed $url = NULL. // Output /posts/view/bar Here are a few more usage examples: URL with named parameters: echo $this->Html->url(array( "controller" => "posts". it returns the REQUEST_URI. "foo" => "bar" )). boolean $full = false) Parameters • $url (mixed) – A routing array. Release 2. • $full (mixed) – Either a boolean to indicate whether or not the base path should be included or an array of options for Router::url() Returns a URL pointing to a combination of controller and action. "action" => "view". "ext" => "rss" )). // Output /posts/view/foo:bar URL with extension: echo $this->Html->url(array( "controller" => "posts". If full is true. otherwise it generates the URL for the controller and action combo. "action" => "list". "bar" )).CakePHP Cookbook Documentation. true). Views . the full base URL will be prepended to the result: echo $this->Html->url(array( "controller" => "posts". 150 Chapter 5.rss URL (starting with ‘/’) with the full base URL prepended: echo $this->Html->url('/posts'. "action" => "view". // Output /posts/list.

x // Output http://somedomain.cakephp. "?" => array("foo" => "bar"). 'http://example.com'. 'class' => 'myform') ). 'charset' => '<meta charset="%s">'. Output: <form action="http://example.8/class-Router. 'javascriptlink' => '<script src="%s"%s></script>'. however if you need to generate HTML for HTML5 you will need to create and load a new tags config file containing the tags you’d like to use.com/posts URL with GET params and named anchor: echo $this->Html->url(array( "controller" => "posts".com" method="post" class="myform"> Changing the tags output by HtmlHelper HtmlHelper::loadConfig(mixed $configFile. Release 2. // Output /posts/search?foo=bar#first For further information check Router::url3 in the API.. HtmlHelper::useTag(string $tag) Returns a formatted existent block of $tag: $this->Html->useTag( 'form'.. To change the tags used create app/Config/html5_tags. "action" => "search". )).php containing: $config = array('tags' => array( 'css' => '<link rel="%s" href="%s" %s>'. 'javascriptstart' => '<script>'. 3 http://api. string $path = null) The built-in tag sets for HtmlHelper are XHTML compliant. // .org/2.CakePHP Cookbook Documentation. You can then load this tag set by calling $this->Html->loadConfig(’html5_tags’).html#_url More about Views 151 . 'javascriptblock' => '<script%s>%s</script>'. 'style' => '<style%s>%s</style>'. array('method' => 'post'. "#" => "first" )).

'Home'). Views . 'escape' => false )).3: The ‘separator’. Changed in version 2. To set this up. 'action' => 'display'. • $startText (string|array) – The text or element that precedes the ul. '/users'). You can use the $startText parameter to provide the first breadcrumb link/text. ‘lastClass’ and ‘escape’ options. 'action' => 'add')).5: The ‘escape’ option was added.1: The $startText parameter was added. Any keys that are not text or url will be passed to link() as the $options parameter. so it uses options which every crumb was added with. Release 2. array $settings = array()) 152 Chapter 5. ‘firstClass’ and ‘lastClass’ options were added. first add something similar to the following in your layout template: echo $this->Html->getCrumbs(' > '.x Creating breadcrumb trails with HtmlHelper HtmlHelper::getCrumbs(string $separator = ‘&raquo. This option works the same as the $startText option for getCrumbs().1: The $startText parameter now accepts an array. Works similar to getCrumbs(). Changed in version 2. Changed in version 2.png'). array('controller' => 'users'. string|array|bool $startText = false) CakePHP has the built-in ability to automatically create a breadcrumb trail in your app. mixed $startText) Parameters • $options (array) – An array of html attributes for the containing <ul> element. This gives more control over the generated first link: echo $this->Html->getCrumbs(' > '. string $link = null. 'home'). ‘firstClass’. HtmlHelper::addCrumb(string $name. Returns breadcrumbs as a (x)html list. mixed $options = null) Now. This will add the output of “Home > Users > Add User” in your layout where getCrumbs was added. This method uses HtmlHelper::tag() to generate list and its elements.’. JsHelper class JsHelper(View $view. This is useful when you always want to include a root link. Changed in version 2. 'url' => array('controller' => 'pages'. Can also contain the ‘separator’. HtmlHelper::getCrumbList(array $options = array(). The $startText option can also accept an array. array( 'text' => $this->Html->image('home. in your view you’ll want to add the following to start the breadcrumb trails on each of the pages: $this->Html->addCrumb('Users'. $this->Html->addCrumb('Add User'.CakePHP Cookbook Documentation.

or YUI). the community has been asking for support for other libraries. Using jQuery with other libraries The jQuery library. use the jQueryObject variable: More about Views 153 . JavaScript engine selection is declared when you include the helper in your controller: public $helpers = array('Js' => array('Jquery')). Mootools/Mootools-more. so you shouldn’t get a clash between jQuery and any other library (like Prototype. and virtually all of its plugins are constrained within the jQuery namespace. but we encourage the community to expand the library compatibility.js will be added to the name). “global” objects are stored inside the jQuery namespace as well. As a general rule. MooTools. JavaScript Engines form the backbone of the new JsHelper. We created an Adapter based helper. jQuery uses “$” as a shortcut for “jQuery” To override the “$” shortcut. and included 3 of the most requested libraries.CakePHP Cookbook Documentation.x. the jQuery engine will be used as the default. include this line just before the ending </body> tag: echo $this->Js->writeBuffer(). Prototype/Scriptaculous. While we still think these are excellent JavaScript libraries.x Warning: The JsHelper is currently deprecated and completely removed in 3.ctp: echo $this->Html->script('jquery'). By default scripts are cached. and jQuery/jQuery UI. there is one caveat: By default. While the API is not as expansive as the previous AjaxHelper we feel that the adapter based solution allows for a more extensible solution giving developers the power and flexibility they need to address their specific application needs. We recommend using regular JavaScript and directly interacting with JavaScript libraries where possible. That said. To include it in all pages. Rather than drop Prototype in favour of another JavaScript library. // Include jQuery library Replace jquery with the name of your library file (. // Write cached scripts Warning: You must include the library in your page and print the cache for the helper to function. Using a specific JavaScript engine First of all download your preferred JavaScript library and place it in app/webroot/js Then you must include the library in your page. To do this at the end of each page. In addition they create an extensible system for others to use. Release 2. there are three engines implemented in the core. As mentioned before. Since the beginning CakePHP’s support for JavaScript has been with Prototype/Scriptaculous. and you must explicitly print out the cache. The above would use the Jquery Engine in the instances of JsHelper in your views. If you do not declare a specific engine. A JavaScript engine translates an abstract JavaScript element into concrete JavaScript code specific to the JavaScript library being used. add this line to the <head> section of app/View/Layouts/default.

array('inline' => false) ). allowing you to collect scripts throughout the view. Note: It is not possible to declare a JavaScript engine inside a custom helper. (method chaining only works in PHP5). You can disable buffering wholesale with the $bufferScripts property or setting buffer => false in methods taking $options. Using the facade features of the JsHelper allows you to leverage the buffering and method chaining features built-in. 154 Chapter 5. this will return the buffer contents in a script tag. and output it in one place.'. DojoEngineHelper is correct. Be sure to declare the JsHelper and its engine on top of the $helpers array in your The selected JavaScript engine may disappear (replaced by the default) from the JsHelper object in your helper.CakePHP Cookbook Documentation. Outputting buffered scripts is done with $this->Js->writeBuffer(). and acts as a facade for the the Engine helper. Warning: controller. echo $this->Html->scriptBlock( 'var $j = jQuery. Furthermore. // Tell jQuery to go into noconflict mode Using the JsHelper inside customHelpers Declare the JsHelper in the $helpers array in your customHelper: public $helpers = array('Js'). if you miss to do so and you will get code that does not fit your JavaScript library. do the helper setup in your controller as follows: public $helpers = array( 'Js' => array('Prototype'). with a few additional restrictions. The JsHelper by default buffers almost all script code generated.noConflict(). They must have the Engine suffix.x $this->Js->JqueryEngine->jQueryObject = '$j'. Creating a JavaScript Engine JavaScript engine helpers follow normal helper conventions. elements and layout. JavaScript engine usage The JsHelper provides a few methods. DojoHelper is not good. Release 2. they should extend JsBaseEngineHelper in order to leverage the most of the new API. Views . Doing that will have no effect. If you are willing to use an other JavaScript engine than the default. 'CustomHelper' ). You should not directly access the Engine helper except in rare occasions.

Options • inline . Is an example of method chaining. Callback wrapping By default all callback options are wrapped with the an anonymous function with the correct arguments. these common options will be mapped out to the library specific options internally.. a common set of options is supported by JsHelper. JsHelper::getBuffer($clear = true) More about Views 155 .wrap cached scripts in domready event (default true) • safe . It is recommended that you place $this->Js->writeBuffer() at the bottom of your layout file above the </body> tag.CakePHP Cookbook Documentation. Release 2. It should be noted that buffered scripts are handled separately from included script files. $this->Js->get() returns a $this. and the inability to buffer scripts added by elements in the layout. Method chaining is not possible in PHP4 and the above sample would be written like: $this->Js->get('#foo'). (default true) • cache .if an inline block is generated should it be wrapped in <![CDATA[ . JsHelper::writeBuffer($options = array()) Writes all JavaScript generated so far to a code block or caches them to a file and returns a linked script. If you are not planning on switching JavaScript libraries.. The new JsHelper if used correctly avoids both of those issues. Method chaining allows you to write shorter. ]]> (default true) Creating a cache file with writeBuffer() requires that webroot/js be world writable and allows a browser to cache generated script resources for any page. allowing you to chain the methods using the selection. $eventCode). Working with buffered scripts One drawback to previous implementation of ‘Ajax’ type features was the scattering of script tags throughout your document. more expressive code: $this->Js->get('#foo')->event('click'. This will allow all scripts generated in layout elements to be output in one place. Common options In attempts to simplify development where JavaScript libraries can change.Set to true to have scripts output as a script block inline if cache is also true.x Since most methods in JavaScript begin with a selection of elements in the DOM. each library also supports all of its native callbacks and options. You can disable this behavior by supplying the wrapCallbacks = false in your options array. a script link tag will be generated. $eventCode).Set to true to have scripts cached to a file and linked in (default false) • clear . $this->Js->event('click'.Set to false to prevent script cache from being cleared (default true) • onDomReady . JsHelper::buffer($content) Add $content to the internal script buffer.

The engines buffer the following methods by default: • event • sortable • drag • drop • slider Additionally you can force any other method in JsHelper to use the buffering. The above would force the each() method to use the buffer. JsHelper::sortable($options = array()) Sortable generates a JavaScript snippet to make a set of elements (usually a list) drag and drop sortable. For example the each() method does not normally buffer: $this->Js->each('alert("whoa!"). 'alert("whoa!"). Views .x Get the contents of the current buffer. JsHelper::object($data.String prepended to the returned data. By appending an boolean to the end of the arguments you can force other methods to go into the buffer. true). This method is a proxy for json_encode() with a few extra features added via the $options parameter. Conversely if you want a method that does buffer to not buffer. $options = array()) Serializes $data into JSON. Release 2. you can pass a false in as the last argument: $this->Js->event('click'.'. Other Methods The core JavaScript Engines provide the same feature set across all libraries. Buffering methods that are not normally buffered Some methods in the helpers are buffered by default. Example Use: $json = $this->Js->object($data). The normalized options are: 156 Chapter 5. there is also a subset of common options that are translated into library specific options. This would force the event function which normally buffers to return its result. Whenever you see separate lists for Options and Event Options both sets of parameters are supplied in the $options array for the method.'.CakePHP Cookbook Documentation. Options: •prefix .String appended to the returned data. •postfix . This is done to provide end developers with as unified an API as possible. The following list of methods are supported by all the Engines included in the CakePHP core. Pass in false to not clear the buffer at the same time. false).

Assuming you were using the jQuery engine.Callback to fire on request failure. you would get the following code in your generated JavaScript block $("#myList"). 'start' => 'onStart'. •opacity . Example Use: $this->Js->get('#my-list').Opacity of the placeholder •distance . Only this element will start sort action. distance:5. $options = array()) Generate a JavaScript snippet to create an XmlHttpRequest or ‘AJAX’ request.Distance a sortable must be dragged before sorting starts. Event Options •complete . •before .sortable({ containment:"parent". 'sort' => 'onSort'. JsHelper::request($url. More about Views 157 .Callback to fire on request initialization.Event fired during sorting •complete . Release 2.Callback to fire on complete. start:onStart. •success .x Options •containment . sort:onSort. Event Options •start . Other options are supported by each JavaScript library. •error .Container for move action •handle .Event fired when sorting starts •sort . 'wrapCallbacks' => false )).Callback to fire on success. •revert . stop:onStop }). 'containment' => 'parent'.Event fired when sorting completes.Selector to handle element. 'complete' => 'onStop'. $this->Js->sortable(array( 'distance' => 5.Whether or not to use an effect to move sortable into final position. and you should check the documentation for your JavaScript library for more detailed information on its options and parameters.CakePHP Cookbook Documentation.

'update' => '#element') ) ). y) •container . Example use: $this->Js->event( 'click'. array('async' => true. The JavaScript variable used to output set variables can be controlled with JsHelper::$setVariable. Default is html for most libraries. •update . call get() again with a new element.CakePHP Cookbook Documentation. •dataExpression . Event Options •start . Views . ‘json’ and ‘html’ are supported.Event fired when the drag starts •drag . To change the active selection.Event fired on every step of the drag 158 Chapter 5. •evalScripts . $this->Js->request( array('action' => 'foo'.Whether or not <script> tags should be eval’ed. JsHelper::get($selector) Set the internal ‘selection’ to a CSS selector.selector to the handle element. •snapGrid . 'param1').The pixel grid that movement snaps to. •data .Should the data key be treated as a callback.The method to make the request with defaults to GET in more libraries •async . an array(x. •type .The element that acts as a bounding box for the draggable element. Useful for supplying $options[’data’] as another JavaScript expression. JsHelper::set(mixed $one. Allows you to set variables that will be output when the buffer is fetched with JsHelper::getBuffer() or JsHelper::writeBuffer(). JsHelper::drag($options = array()) Make an element draggable. Options •handle .Dom id to update with the content of the response.Whether or not you want an asynchronous request.Data type for response. mixed $two = null) Pass variables into JavaScript.Additional data to send.x Options •method . The active selection is used in subsequent operations until a new selection is made: $this->Js->get('#element'). The JsHelper now will reference all other element based methods on the selection of #element. Release 2.

Event fired when dragging stops (mouse release) Example use: $this->Js->get('#element'). More about Views 159 . •hoverclass . start:onStart. 'wrapCallbacks' => false )). Example use: $this->Js->get('#element'). 'leave' => 'onExit'. drag:onDrag.items'. Event Options •drop . 'stop' => 'onStop'. 'drag' => 'onDrag'. 'start' => 'onStart'. grid:[10. •leave .droppable({ accept:".draggable({ containment:"#content".x •stop .CakePHP Cookbook Documentation.10]. $this->Js->drag(array( 'container' => '#content'. Options •accept . 'hover' => 'onHover'.Selector for elements this droppable will accept. JsHelper::drop($options = array()) Make an element accept draggable elements and act as a dropzone for dragged elements. If you were using the jQuery engine the following code would be added to the buffer $("#element").items". 10). stop:onStop }). If you were using the jQuery engine the following code would be added to the buffer $("#element").Event fired when a drag is removed from a drop zone without being dropped. 'drop' => 'onDrop'. 'wrapCallbacks' => false )).Event fired when a drag enters a drop zone.Class to add to droppable when a draggable is over. 'snapGrid' => array(10. $this->Js->drop(array( 'accept' => '. Release 2. •hover .Event fired when an element is dropped into the drop zone. drop:onDrop.

Furthermore. So in addition to making a get() selection for the droppable element. •value .The min value for the slider. Droppables are implemented as an extension of Drag. •direction . Views . stop:onComplete.x out:onExit. $this->Js->slider(array( 'complete' => 'onComplete'. 'max' => 10. min:0. If you were using the jQuery engine the following code would be added to the buffer $("#element"). See your libraries implementation for additional usage and features. 'direction' => 'vertical'. orientation:"vertical".The id of the element used in sliding. 'min' => 0. over:onHover }). You must also provide a selector rule to the draggable element.CakePHP Cookbook Documentation. Mootools droppables inherit all options from Drag. Options •handle . max:10.slider({ change:onChange. 'change' => 'onChange'.The initial offset of the slider.Fired when the user stops sliding the handle Example use: $this->Js->get('#element'). JsHelper::slider($options = array()) Create snippet of JavaScript that converts an element into a slider ui widget. Note: Droppables in Mootools function differently from other libraries. •max .Fired when the slider’s value is updated •complete .The number of steps or ticks the slider will have.The direction of the slider either ‘vertical’ or ‘horizontal’ •min . 'value' => 2. Events •change .The max value for the slider. 'wrapCallbacks' => false )). 160 Chapter 5. Release 2. •step .

.fadeIn().Fade out an element. Release 2.bind('click'. •hide . } unless disabled with the $options. More about Views 161 . $this->Js->alert('hey you!')). JsHelper::event($type. (defaults to true) Example use: $this->Js->get('#some-link'). Example use If you were using the jQuery engine: $this->Js->get('#element').Whether you want the event to stop.x value:2 }).. Accepted values are ‘slow’. JsHelper::effect($name. If you were using the jQuery library you would get the following JavaScript code: $('#some-link').CakePHP Cookbook Documentation. Options •speed . $content.Fade in an element. •slideIn . // $result contains $("#foo"). $type can be any of the normal DOM events or a custom event type if your library supports them. Supported effect names The following effects are supported by all JsEngines •show .reveal an element. •slideOut .Slide an element out. (defaults to true) •stop . Not all effects use the speed option.Whether you want the callback wrapped in an anonymous function. $content should contain the function body for the callback. Callbacks will be wrapped with function (event) { .hide an element.Speed at which the animation should occur. By default this method is not buffered and returns its result.Slide an element in. •fadeOut . $this->Js->event('click'. •fadeIn . ‘fast’. function (event) { alert('hey you!'). $result = $this->Js->effect('fadeIn'). $options = array()) Creates a basic effect. Options •wrap . $options = array()) Bind an event to the current selection.

'blue'). Example: $this->Js->get('div. confirm does not buffer. }). JsHelper::domReady($callback) Creates the special ‘DOM ready’ event. }). Release 2. If you were using the jQuery library you would the following JavaScript code would be added to the buffer.each(function () { $(this). $this->Js->event( 'click'. JsHelper::each($callback) Create a snippet that iterates over the currently selected elements. By default. function (event) { alert('hey you!').css({color: "red"}). and returns the script snippet.'). and returns the script snippet. array('stop' => false) ). JsHelper::writeBuffer() automatically wraps the buffered scripts in a domReady method. $this->Js->alert('hey you!'). JsHelper::alert($message) Create a JavaScript snippet containing an alert() snippet. prompt does not buffer. Using the jQuery engine would create the following JavaScript: $('div. and inserts $callback. Note that the default browser event is not cancelled: $('#some-link'). By default. by passing setting the stop option to false: $this->Js->get('#some-link'). $prompt = $this->Js->prompt('What is your favorite color?'.x return false.message').css({color: "red"}). and returns the script snippet. }). JsHelper::confirm($message) Create a JavaScript snippet containing a confirm() snippet.message').CakePHP Cookbook Documentation. Views . You can remove the return false.bind('click'. alert does not buffer. JsHelper::prompt($message. By default. 162 Chapter 5. $alert = $this->Js->alert('Hey there'). $this->Js->each('$(this). $default) Create a JavaScript snippet containing a prompt() snippet. $alert = $this->Js->confirm('Are you sure?').

echo $this->Js->submit('Save'. $options is a html attributes array that are appended to the generated anchor element. JsBaseEngine::event(). or other more specialized setups that are beyond the scope of this helper. Release 2. JsHelper::event(). does not replace any before callback methods in the generated XmlHttpRequest. Options •confirm . $options = array()) Create an HTML anchor element that has a click event bound to it. $options = array()) Create a submit input button that enables XmlHttpRequest submitted forms. •buffer . If an id is not supplied. The click event will be buffered by default. rel. •id . Example use: echo $this->Js->submit('Save'.CakePHP Cookbook Documentation.additional non-standard htmlAttributes. id.Generate a confirm() dialog before sending the event. Options can include both those for HtmlHelper::link() and JsHelper::request(). If an option is not part of the standard attributes or $htmlAttributes it will be passed to JsHelper::request() as an option. Options •url . Shows how you can combine options that JsHelper::request() when using submit. array( 'update' => '#content'. a randomly generated one will be created for each link generated.Disable the buffering and return a script tag in addition to the link. array('page' => 2). Example use: echo $this->Js->link( 'Page 2'. 'type' => 'json'.Set to false to disable automatic callback wrapping. both FormHelper::submit() and JsHelper::link($title.Confirm message displayed before sending the request. Forms submitting with this method. escape. 'async' => false )). title. •htmlAttributes . Standard attributes are class.The URL you wish the XHR request to submit to. cannot send files. array('update' => '#content')). Files do not transfer over XmlHttpRequest and require an iframe. •wrapCallbacks . onblur and onfocus. More about Views 163 . Using confirm.use a custom id. 'div' => false. Will create a submit button with an attached onclick event.x JsHelper::submit($caption = null. $url = null. Options can include both those for FormHelper::submit() and JsBaseEngine::request(). •confirm . •buffer .Disable the buffering and return a script tag in addition to the link.

You can use the htmlAttributes option to add in additional custom attributes.location. Escapes any string values into JSON compatible strings. AJAX Pagination Much like AJAX Pagination in 1. Add the following to your controller: public $components = array('RequestHandler').x array('update' => '#content') ). This is useful when you need to serialize a form element as part of another JavaScript operation.is the rendered statement going to be used inside another JS statement? (defaults to false) Setting inline == false allows you to remove the trailing . So in your layout include jQuery (or whichever library you are using). or use the serialize method in an Object literal.. public $helpers = array('Js'). Release 2. echo $this->Js->link('Page 2'. array('page' => 2). array( 'update' => '#content'.is the current selection a form. Views . you can use the JsHelper to handle the creation of AJAX pagination links instead of plain HTML links. Pass true for $isForm if the current selection is a form element.CakePHP Cookbook Documentation. Outputs the following HTML: <a href="/posts/index/page:2" other="value">Page 2</a> JsHelper::serializeForm($options = array()) Serialize the form attached to $selector. Converts the form or the form element attached to the current selection into a string/json object (depending on the library implementation) for use with XHR operations. Also make sure to include RequestHandlerComponent in your components. For this example we’ll be using jQuery: 164 Chapter 5.2. UTF-8 characters will be escaped. Making AJAX Links Before you can create AJAX links you must include the JavaScript library that matches the adapter you are using with JsHelper. or an input? (defaults to false) •inline . 'htmlAttributes' => array('other' => 'value') )). Options •isForm . JsHelper::redirect($url) Redirect the page to $url using window. JsHelper::value($value) Converts a PHP-native variable of any type to a JSON-equivalent representation. By default the JsHelper uses jQuery. Next link in the JavaScript library you want to use. Will create a link pointing to /page:2 and updating #content with the response.

} in your main CSS file. and often times you want to wrap $content_for_layout with a div matching the id used for the update option. Release 2.2 you need to tell the PaginatorHelper that you want to make JavaScript enhanced links instead of plain HTML ones. so you don’t have worry about the same JavaScript being output twice. Since the JsHelper automatically buffers all generated script content to reduce the number of <script> tags in your source code you must write the buffer out.CakePHP Cookbook Documentation. Be sure to include: echo $this->Js->writeBuffer(). 'evalScripts' => true )). you must add any indicator effects yourself: <!DOCTYPE html> <html> <head> <?php echo $this->Html->script('jquery').gif file inside app/webroot/img folder. If you omit this you will not be able to chain AJAX pagination links. The indicator option is not supported by JsHelper and will be ignored. ?> </body> </html> Remember to place the indicator.gif'. To do so.gif displays immediately upon the page load. ?> //more stuff here. You also should set evalScripts to true if you are using the Mootools or Prototype adapters. At the bottom of your view file. When you write the buffer. without evalScripts these libraries will not be able to chain requests together. it is also cleared. You then create all the links as needed for your pagination features. Adding effects and transitions Since indicator is no longer supported. </head> <body> <div id="content"> <?php echo $this->fetch('content'). array('id' => 'busy-indicator') ). Similar to 1. ?> </div> <?php echo $this->Html->image( 'indicator. More about Views 165 . Of course this element must exist. You may see a situation where the indicator.x echo $this->Html->script('jquery'). You need to put in this CSS #busy-indicator { display:none. and that those links should update the #content element. The PaginatorHelper now knows to make JavaScript enhanced links. call the options() at the top of your view: $this->Paginator->options(array( 'update' => '#content'.

format numbers to specific precisions and also to give you more flexibility with formatting numbers. Although indicator has been removed. 'complete' => $this->Js->get('#busy-indicator')->effect( 'fadeOut'. Views . This will show/hide the busy-indicator element before and after the #content div is updated. To do that we need to update our options() function: $this->Paginator->options(array( 'update' => '#content'. the new features offered by JsHelper allow for more control and more complex effects to be created. They do not automatically echo the output into the view. Usage in a view looks like: // called as NumberHelper echo $this->Number->currency($number. 'before' => $this->Js->get('#busy-indicator')->effect( 'fadeIn'. $currency). Within a view.GBP. these methods are accessible via the NumberHelper class and you can call it as you would call a normal helper method: $this->Number->method($args). // called as CakeNumber App::uses('CakeNumber'.1: NumberHelper have been refactored into CakeNumber class to allow easier use outside of the View layer. • $options (array) – Options. These methods include ways to format currency. array('buffer' => false) ). array $settings = array()) The NumberHelper contains convenient methods that enable display numbers in common formats in your views. Changed in version 2. we’ve included an indicator image file.x With the above layout. 166 Chapter 5.. NumberHelper::currency(float $number. $currency). see below. that will display a busy indicator animation that we will show and hide with the JsHelper. All of these functions return the formatted number.USD). percentages. echo CakeNumber::currency($number.CakePHP Cookbook Documentation. )). 'Utility'). array $options = array()) Parameters • $number (float) – The value to covert. NumberHelper class NumberHelper(View $view. 'evalScripts' => true. data sizes. • $currency (string) – The known currency format to use. Release 2. string $currency = ‘USD’. array('buffer' => false) ). This method is used to display a number in common currency formats (EUR.

eg. Set to boolean false to use no decimal symbol. For example: // called as NumberHelper echo $this->Number->currency('1234. 0. The text to use for zero values. If a non-recognized $currency value is supplied. ‘. ‘Free!’ Number of decimal places to use.56.56 $1.CakePHP Cookbook Documentation. 'FOO'). ‘. // Outputs FOO 1.234. NumberHelper::defaultCurrency(string $currency) Parameters More about Views 167 . 2 Thousands separator ie. $number. should be a floating point number that represents the amount of money you are expressing. ‘ dollars’ Either ‘before’ or ‘after’ to place the whole symbol String to use for fraction numbers ie.’ Decimal separator symbol ie. formatted by currency type C1. ‘c’. Release 2.’ Symbol for negative numbers. Changed in version 2.234. If equal to ‘()’. The following options are available: Option before after zero places thousands decimals negative escape wholeSymbol wholePosition fractionSymbol fractionPosition fractionExponent Description The currency symbol to place before whole numbers ie. ‘$’ The currency symbol to place after decimal numbers ie.234.x The first parameter. ie.56 £1.35. the number will be wrapped with ( and ) Should the output be htmlentity escaped? Defaults to true String to use for whole numbers ie.56'. 0.35 => $0.234. can be a string or a number. The second parameter is used to choose a predefined currency formatting scheme: $currency EUR GBP USD 1234. it is prepended to a USD formatted number.4: The fractionExponent option was added. ie.56 The third parameter is an array of options for further defining the output. ‘ cents’ Either ‘before’ or ‘after’ to place the fraction symbol Fraction exponent of this specific currency. 'Utility').56 // called as CakeNumber App::uses('CakeNumber'. Defaults to 2. echo CakeNumber::currency('1234.56'. 'FOO').

'. Views . Added formats are merged with the following defaults: array( 'wholeSymbol' 'wholePosition' 'fractionSymbol' 'fractionPosition' 'zero' 'places' 'thousands' 'decimals' 'negative' 'escape' 'fractionExponent' ) => => => => => => => => => => => ''. CakeNumber::addFormat('BRL'. Setter/getter for default currency. 2.'. false. 0. echo CakeNumber::currency($value. 2 NumberHelper::precision(mixed $number.CakePHP Cookbook Documentation. New in version 2.'. 'decimals' // called as CakeNumber App::uses('CakeNumber'. 'Utility'). 'BRL'). Makes reusing currency formats easier: // called as NumberHelper $this->Number->addFormat('BRL'. 'thousands' => '.'. array $options) Parameters • $formatName (string) – The format name to be used in the future • $options (array) – The array of options for this format. true. $options keys as CakeNumber::currency(). Release 2. 'BRL'). '()'. '.3: This method was added in 2.3 NumberHelper::addFormat(string $formatName.x • $currency (string) – Set a known currency for CakeNumber::currency(). array('before' => 'R$'. 'decimals' => You can now use BRL as a short form when formatting currency amounts: // called as NumberHelper echo $this->Number->currency($value. 'after'. // called as CakeNumber App::uses('CakeNumber'. '. 'before'. int $precision = 3) Parameters • $number (float) – The value to covert • $precision (integer) – The number of decimal places to display 168 Chapter 5. Uses the same Add a currency format to the Number helper. 'thousands' => '. 'Utility'). This removes the need always passing the currency to CakeNumber::currency() and change all currency outputs by setting other default. array('before' => 'R$'.

This method also expresses the number as a percentage and prepends the output with a percent sign.3: This method was added in 2. Release 2. int $precision = 2. New in version 2. 2). // called as NumberHelper echo $this->Number->precision(456.92 // called as CakeNumber App::uses('CakeNumber'. 2. 'Utility'). $default) Parameters • $size (string) – The formatted human readable value.CakePHP Cookbook Documentation. // Called as NumberHelper. Output: 45. • $precision (integer) – The number of decimal places to display.691873645).4: The $options argument with the multiply option was added. Output: 45. New in version 2. NumberHelper::toPercentage(mixed $number. Output: 45. array $options = array()) Parameters • $number (float) – The value to covert. This method unformats a number from a human readable byte size to an integer number of bytes. // Called with multiply. echo CakeNumber::precision(456.x This method displays a number with the specified amount of precision (decimal places). NumberHelper::fromReadableSize(string $size.91873645. echo CakeNumber::toPercentage(45. Option multiply Description Boolean to indicate whether the value has to be multiplied by 100. • $options (array) – Options. 'Utility'). It will round in order to maintain the level of precision defined. array( 'multiply' => true )). // Called as CakeNumber.45691. Useful for decimal percentages.69% echo $this->Number->toPercentage(45.91873645.3 NumberHelper::toReadableSize(string $dataSize) More about Views 169 . this method formats a number according to the supplied precision (where numbers are rounded to meet the given precision).69% App::uses('CakeNumber'.691873645). see below. 2). Like precision().69% echo CakeNumber::toPercentage(0. // Outputs 456.

The $options parameter is where the real magic for this method resides. places Example: // called as NumberHelper echo $this->Number->format('123456. // 1.7890'. $options). Using this method might looks like: // called as NumberHelper $this->Number->format($number.e. // 0 Bytes echo $this->Number->toReadableSize(1024). // 1.26 MB echo $this->Number->toReadableSize(5368709120). 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).334 would output as 1. The size is displayed with a two-digit precision level.00 GB NumberHelper::format(mixed $number. and TB.00 GB // called as CakeNumber App::uses('CakeNumber'. MB. // 5. •If you pass an associated array. This method formats data sizes in human readable forms. Views . Note that the default precision is zero decimal places.76). . The $number parameter is the number that you are planning on formatting for output. 'Utility'). $options). . 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. With no $options supplied.CakePHP Cookbook Documentation. Release 2. // 0 Bytes echo CakeNumber::toReadableSize(1024).236. GB. according to the size of data supplied (i.26 MB echo CakeNumber::toReadableSize(5368709120). higher sizes are expressed in larger terms): // called as NumberHelper echo $this->Number->toReadableSize(0).76). // 1 KB echo $this->Number->toReadableSize(1321205. // called as CakeNumber CakeNumber::format($number. the number 1236. array( 'places' => 2. It provides a shortcut way to convert bytes to KB. millions. // 5.x Parameters • $dataSize (string) – The number of bytes to make readable. echo CakeNumber::toReadableSize(0). . •If you pass an integer then this becomes the amount of precision or places for the function. 170 Chapter 5. // 1 KB echo CakeNumber::toReadableSize(1321205.

'before' => '¥ '. // called as CakeNumber CakeNumber::formatDelta($number.79' // called as CakeNumber App::uses('CakeNumber'.456. // output '¥ 123.'. places Example: // called as NumberHelper echo $this->Number->formatDelta('123456.' )).' )). .236. array( 'places' => 2.'. 'Utility').79' NumberHelper::formatDelta(mixed $number. 'thousands' => '. . The $number parameter is the number that you are planning on formatting for output. With no $options supplied. // output '+123. 'escape' => false. 'thousands' => '.' )).7890'. // output '¥ 123.'. 'Utility'). $options). mixed $options=array()) This method displays differences in value as a signed number: // called as NumberHelper $this->Number->formatDelta($number. $options).7890'.x 'before' => '¥ '.334 would output as 1.456.456.79' // called as CakeNumber App::uses('CakeNumber'. 'decimals' => '. 'thousands' => '. 'escape' => false. the number 1236. Note that the default precision is zero decimal places. 'decimals' => '.CakePHP Cookbook Documentation. millions. 'decimals' => '. More about Views 171 . Release 2. array( 'places' => 2. The $options parameter takes the same keys as CakeNumber::format() itself: •places (integer): the amount of desired precision •before (string): to be put before the outputted number •after (string): to be put after the outputted number •decimals (string): used to delimit the decimal places in a number •thousands (string): used to mark off thousand. echo CakeNumber::format('123456. .

Links will default to sorting by asc. Release 2. Link sorting default by ‘asc’. Views . • lock Lock direction.3 Warning: Since 2. Please see the migration guide for details if you run a non-UTF-8 app. Generates a sorting link. PaginatorHelper class PaginatorHelper(View $view. $options = array()) Parameters • $key (string) – The name of the key that the recordset should be sorted. 'decimals' => '. • direction The default direction to use when this link isn’t active.79' New in version 2. array $settings = array()) The Pagination helper is used to output pagination controls such as page numbers and next/previous links.x echo CakeNumber::formatDelta('123456. Sets named or querystring parameters for the sort and direction.'.5: You can now set the lock option to true in order to lock the sorting direction into the specified direction.3: This method was added in 2. • $options (array) – Options for sorting link. Creating sort links PaginatorHelper::sort($key. 'thousands' => '. After the first click. Accepted keys for $options: • escape Whether you want the contents HTML entity encoded.' )). • $title (string) – Title for the link. • model The model to use. Assuming you are paginating some posts. defaults to false. New in version 2. If the resultset is sorted ‘asc’ by the specified key the returned link will sort by ‘desc’. and are on page one: 172 Chapter 5. $title = null.CakePHP Cookbook Documentation.456. If $title is null $key will be used for the title and will be generated by inflection. links generated with sort() will handle direction switching automatically. defaults to true. // output '+123. See also Pagination for information on how to create paginated datasets and do paginated queries.7890'. array( 'places' => 2.4 the symbols are now UTF-8. It works in tandem with PaginatorComponent. defaults to PaginatorHelper::defaultModel(). Will only use the default direction then.

'User account'). it will automatically switch directions like normal: echo $this->Paginator->sort('user_id'.x echo $this->Paginator->sort('user_id'). mixed $options = array()) Gets the current direction the recordset is sorted. array('escape' => false) ). PaginatorHelper::sortDir(string $model = null. Links will not be generated for pages that do not exist. Output: <a href="/posts/index/page:1/sort:user_id/direction:desc/">User Id</a> The lock option can be used to lock sorting into the specified direction: echo $this->Paginator->sort('user_id'. Creating page number links PaginatorHelper::numbers($options = array()) Returns a set of numbers for the paged result set. PaginatorHelper::sortKey(string $model = null. 'lock' => true)). Output: <a href="/posts/index/page:1/sort:user_id/direction:asc/">User account</a> If you are using HTML like images in your links remember to set escaping off: echo $this->Paginator->sort( 'user_id'.CakePHP Cookbook Documentation. Uses a modulus to decide how many numbers to show on each side of the current page By default 8 links on either side of the current page will be created if those pages exist. Release 2. Once a link is active. null. array('direction' => 'asc'. The current page is also not a link. array('direction' => 'desc')). mixed $options = array()) Gets the current key by which the recordset is sorted. Output: <a href="/posts/index/page:1/sort:user_id/direction:asc/"> <em>User account</em> </a> The direction option can be used to set the default direction for a link. null. Output: <a href="/posts/index/page:1/sort:user_id/direction:asc/">User Id</a> You can use the title parameter to create custom text for your link: echo $this->Paginator->sort('user_id'. More about Views 173 . '<em>User account</em>'.

set to an integer to define the number of ‘last’ links to generate. defaults to ‘span’. echo $this->Paginator->numbers(). Release 2.1. While this method allows a lot of customization for its output. defaults to 8. defaults to null.3: The currentTag option was added in 2. • after Content to be inserted after the numbers.. The following would create a set of page links that include links to the first 2 and last 2 pages in the paged results: echo $this->Paginator->numbers(array('first' => 2. • separator Separator content defaults to ‘‘ | ‘‘ • tag The tag to wrap links in. Views . defaults to PaginatorHelper::defaultModel(). New in version 2.CakePHP Cookbook Documentation. • model Model to create numbers for. • modulus how many numbers to include on either side of the current page. There is a last()‘ method to be used separately as well if you wish. • ellipsis Ellipsis content. $disabledOptions = array()) Parameters 174 Chapter 5. defaults to ‘. set to an integer to define the number of ‘first’ links to generate. Follows the same logic as the first option. If a string is set a link to the first page will be generated with the value as the title: echo $this->Paginator->numbers(array('first' => 'First page')).. • last Whether you want last links generated.’ • class The class name used on the wrapping tag. New in version 2. Defaults to false.3. • currentTag Tag to use for current page number. 'last' => 2)). Defaults to current. Using the first and last options you can create links to the beginning and end of the page set. you’ll often want links that go to the previous and next links. first and last pages in the paged data set. $options = array(). This allows you to generate for example Twitter Bootstrap like links with the current page number wrapped in extra ‘a’ or ‘span’ tag.x Supported options are: • before Content to be inserted before the numbers. It is also ok to just call the method without any params. Creating jump links In addition to generating links that go directly to specific page numbers. Defaults to false. • currentClass The class name to use on the current/active link. • first Whether you want first links generated. $disabledTitle = null.1: The currentClass option was added in 2. PaginatorHelper::prev($title = ‘<< Previous’.

Generates a link to the previous page in a set of paged records. array(). defaults to ‘span’. $options and $disabledOptions supports the following keys: •tag The tag wrapping tag you want to use. If you were currently on the second page of posts. •model The model to use. array('tag' => 'li')). Release 2. no previous page to go. as when you’re already on the first page. • $options (mixed) – Options for pagination link. • $disabledTitle (string) – Title when the link is disabled. array('class' => 'prev disabled') ). Output: <li class="prev"> <a rel="prev" href="/posts/index/page:1/sort:title/order:desc"> previous </a> </li> You can also disable the wrapping tag: More about Views 175 . defaults to true.CakePHP Cookbook Documentation. null. Set this to false to disable this option. __('previous'). •disabledTag Tag to use instead of A tag when there is no previous page A simple example would be: echo $this->Paginator->prev( ' << ' . defaults to PaginatorHelper::defaultModel().x • $title (string) – Title for the link. • $disabledOptions (mixed) – Options for the disabled pagination link. •escape Whether you want the contents HTML entity encoded. you would get the following: <span class="prev"> <a rel="prev" href="/posts/index/page:1/sort:title/order:desc"> << previous </a> </span> If there were no previous pages you would get: <span class="prev disabled"><< previous</span> You can change the wrapping tag using the tag option: echo $this->Paginator->prev(__('previous').

$options = array()) This method works very much like the first() method. It will not generate any links if you are on the last page for a string values of $last. If a string is given. The above creates a single link for the first page. You can also use an integer to indicate how many first paging links you want generated: echo $this->Paginator->first(3). PaginatorHelper::current(string $model = null) Gets the current page of the recordset for the given model: 176 Chapter 5.3: For methods: PaginatorHelper::prev() and PaginatorHelper::next() it is now possible to set the tag option to false to disable the wrapper. defaults to ‘. $options = array()) Returns a first or set of numbers for the first pages. defaults to ‘ | ‘ •ellipsis Content for ellipsis. then only a link to the first page with the provided text will be created: echo $this->Paginator->first('< first'). $disabledOptions = array()) This method is identical to prev() with a few exceptions. $disabledTitle = null. It creates links pointing to the next page instead of the previous one. It also uses next as the rel attribute value instead of prev PaginatorHelper::first($first = ‘<< first’. defaults to ‘span’ •after Content to insert after the link/tag •model The model to use defaults to PaginatorHelper::defaultModel() •separator Content between the generated links. $options = array(). Prior to that nothing will be output. The above will create links for the first 3 pages. once you get to the third or greater page. Will output nothing if you are on the first page.’ PaginatorHelper::last($last = ‘last >>’. PaginatorHelper::next($title = ‘Next >>’..x echo $this->Paginator->prev(__('previous'). The options parameter accepts the following: •tag The tag wrapping tag you want to use. New options disabledTag has been added.CakePHP Cookbook Documentation. Output: <a class="prev" rel="prev" href="/posts/index/page:1/sort:title/order:desc"> previous </a> Changed in version 2. This can save some additional typing if both sets of options are the same.. For an integer value of $last no links will be generated once the user is inside the range of last pages. If you leave the $disabledOptions empty the $options parameter will be used. Release 2. It has a few differences though. array('tag' => false)). Views .

starting on record {:start}. {:model} would be ‘recipe pages’.0. – {:end} . The supported ones are: • format Format of the counter. If your model was ‘RecipePage’.3 of 13’: echo $this->Paginator->counter(array( 'format' => 'range' )). Creating a page counter PaginatorHelper::counter($options = array()) Returns a counter string for the paged result set. In the custom mode the supplied string is parsed and tokens are replaced with actual values.number of the last record being displayed. Using a provided format string and a number of options you can create localized and application specific indicators of where a user is in the paged data set. – {:count} . – {:pages} . ‘pages’ and custom. Defaults to pages which would output like ‘1 of 10’.number of the first record being displayed.total number of pages.the current page displayed. Release 2. There are a number of options for counter(). – {:current} . – {:start} . Setting ‘format’ to range would output like ‘1 . For example: echo $this->Paginator->counter( 'Page {:page} of {:pages}. showing {:current} records out of {:count} total. PaginatorHelper::hasPrev(string $model = null) Returns true if the given result set is not at the first page. PaginatorHelper::hasPage(string $model = null.com/comments/view/page:3 echo $this->Paginator->current('Comment'). This option was added in 2.the total number of records in the result set. ending on {:end}' ). – {:model} . integer $page = 1) Returns true if the given result set has the page number given by $page. More about Views 177 . // Output is 3 PaginatorHelper::hasNext(string $model = null) Returns true if the given result set is not at the last page.x // Our URL is: http://example. Supported formats are ‘range’. You could also supply only a string to the counter method using the tokens available.CakePHP Cookbook Documentation.The pluralized human form of the model name. The available tokens are: – {:page} .current number of records being shown.

'page' => 6. direction and page values. Defaults to true. This is useful when doing AJAX Pagination. Views . Release 2. By default PaginatorHelper will merge in all of the current pass and named parameters. Modifying the options PaginatorHelper uses PaginatorHelper::options($options = array()) Parameters • $options (mixed) – Default options for pagination links. Supported options are: • url The URL of the paginating action. This is used in conjunction with the custom string on ‘format’ option. You can also append additional URL content into all URLs generated in the helper: $this->Paginator->options(array( 'url' => array( 'sort' => 'email'.CakePHP Cookbook Documentation. 'direction' => 'desc'. – page The page number to display. The above mentioned options can be used to force particular pages/directions. • model The name of the model being paginated. 178 Chapter 5. but most often is simpler to use an id selector. The above adds the en route parameter to all links the helper will generate.x • separator The separator between the actual page and the number of pages. • update The CSS selector of the element to update with the results of AJAX pagination calls. 'lang' => 'en' ) )). defaults to PaginatorHelper::defaultModel(). If not specified. It will also create links with specific sort. So you don’t have to do that in each view file. • escape Defines if the title field for links should be HTML escaped. Defaults to ‘ASC’. ‘url’ has a few sub options as well: – sort The key that the records are sorted by. Keep in mind that the value of update can be any valid CSS selector. If a string is supplied .it is used as the DOM id element to update. This is used in conjunction with ‘format’ = ‘pages’ which is ‘format’ default value: echo $this->Paginator->counter(array( 'separator' => ' of a total of ' )). Defaults to ‘ of ‘. – direction The direction of the sorting. regular links will be created: $this->Paginator->options(array('update' => '#content')). Sets all the options for the Paginator Helper.

CakePHP Cookbook Documentation. the PaginatorHelper also offers sorting features which can be easily integrated into your table column headers: // app/View/Posts/index. As mentioned. you have some additional control in the view. 'Title'). Will change the PaginatorHelper to use the CustomJs for AJAX operations. However. ?> </td> <td><?php echo h($recipe['Recipe']['title']).x • model The name of the model PaginatorHelper::defaultModel(). The examples below assume a tabular layout. but most often this will be done inside HTML tables. defaults to Using GET parameters for pagination Normally Pagination in CakePHP uses Named Parameters. 'keys'. Release 2. if you don’t want that and want to use a custom helper for AJAX links.org/2. ?> </td> </tr> <?php endforeach. $this->helpers['Paginator'] = array('ajax' => 'CustomJs'). ?></th> </tr> <?php foreach ($data as $recipe): ?> <tr> <td><?php echo $recipe['Recipe']['id']. as long as that class implements a link() method that behaves like HtmlHelper::link() Pagination in Views It’s up to you to decide how to show records to the user. you can do so by changing the $helpers array in your controller.8/class-PaginatorHelper. You could also set the ‘ajax’ key to be any helper. While the main configuration option for this feature is in PaginatorComponent.cakephp. After running paginate() do the following: // In your controller action. 'here') )). ?> </table> 4 http://api. but the PaginatorHelper available in views doesn’t always need to be restricted as such. Configuring the PaginatorHelper to use a JavaScript helper By default the PaginatorHelper uses JsHelper to do AJAX features. $this->paginate()). $this->set('posts'. 'ID'). ?></th> <th><?php echo $this->Paginator->sort('title'.html More about Views 179 . being paginated. See the details on PaginatorHelper4 in the API. You can use options() to indicate that you want other named parameters to be converted: $this->Paginator->options(array( 'convertKeys' => array('your'. There are times you want to use GET parameters instead.ctp <table> <tr> <th><?php echo $this->Paginator->sort('id'.

// prints X of Y. ?></th> </tr> <?php foreach ($data as $recipe): ?> <tr> <td><?php echo h($recipe['Recipe']['title']). Other Methods PaginatorHelper::link($title. Release 2. ending on {:end}' )). array('class' => 'disabled') ). also supplied by the PaginationHelper: // Shows the page numbers echo $this->Paginator->numbers(). 'Author'). where X is current page and Y is number of pages echo $this->Paginator->counter(). $options = array()) Parameters 180 Chapter 5.CakePHP Cookbook Documentation. Views . null. showing {:current} records out of {:count} total. // Shows the next and previous links echo $this->Paginator->prev( '« Previous'. ?></th> <th><?php echo $this->Paginator->sort('Author. echo $this->Paginator->next( 'Next »'. It is also possible to sort a column based on associations: <table> <tr> <th><?php echo $this->Paginator->sort('title'. ?> </td> </tr> <?php endforeach. ?> </td> <td><?php echo h($recipe['Author']['name']). The wording output by the counter() method can also be customized using special markers: echo $this->Paginator->counter(array( 'format' => 'Page {:page} of {:pages}. null. ?> </table> The final ingredient to pagination display in views is the addition of page navigation. array('class' => 'disabled') ). null. $url = array(). starting on record {:start}. 'Title').name'. null.x The links output from the sort() method of the PaginatorHelper allow users to click on table headers to toggle the sorting of the data by a given field.

defaults to true. •escape Whether you want the contents HTML entity encoded. Creates AJAX enabled links. Defaults to false.x • $title (string) – Title for the link. PaginatorHelper::params(string $model = null) Gets the current paging parameters from the resultset for the given model: debug($this->Paginator->params()). true). • $url (mixed) – Url for the action. 'direction' => 'desc')). Creates a regular or AJAX link with pagination parameters: echo $this->Paginator->link('Sort by title on page 5'. echo $this->Paginator->url(array('sort' => 'title'). See Router::url() • $options (array) – Options for the link. $asArray = false. 'page' => 5. • $asArray (boolean) – Return the URL as an array.e. array('sort' => 'title'.CakePHP Cookbook Documentation. or a URI string. • $model (string) – Which model to paginate on By default returns a full pagination URL string for use in non-standard contexts (i. defaults to PaginatorHelper::defaultModel(). •model The model to use. As used on options() or link() method. See options() for list of keys. If created in the view for /posts/index ‘/posts/index/page:5/sort:title/direction:desc’ Would create a link pointing at PaginatorHelper::url($options = array(). PaginatorHelper::defaultModel() Gets the default model of the paged sets or null if pagination is not initialized. /* Array ( [page] => 2 [current] => 2 [count] => 43 [prevPage] => 1 [nextPage] => 3 [pageCount] => 3 [order] => [limit] => 20 [options] => Array ( More about Views 181 . Release 2. Accepted keys for $options: •update The Id of the DOM element you wish to update. JavaScript). $model = null) Parameters • $options (array) – Pagination/URL options array.

string $model = null) Gets the specific paging parameter from the resultset for the given model: debug($this->Paginator->param('count')).4.CakePHP Cookbook Documentation. Before we jump too far ahead trying to get our webservice up and running we need to do a few things. // Example output for page 5 /* <link href="/?page=4" rel="prev" /><link href="/?page=6" rel="next" /> */ You can also append the output of the meta function to the named block: $this->Paginator->meta(array('block' => true)).rss to posts/index making your URL posts/index.rss. Views . /* (int)43 */ New in version 2.php: 182 Chapter 5. the “meta” block is used.x [page] => 2 [conditions] => Array ( ) ) [paramType] => named ) */ PaginatorHelper::param(string $key. Creating an RSS feed with the RssHelper This example assumes you have a Posts Controller and Post Model already created and want to make an alternative view for RSS. array $settings = array()) The RSS helper makes generating XML for RSS feeds easy. PaginatorHelper::meta(array $options = array()) Outputs the meta-links for a paginated result set: echo $this->Paginator->meta(). this is done in app/Config/routes. Creating an xml/rss version of posts/index is a snap with CakePHP.6: The meta() method was added in 2.4: The param() method was added in 2. RssHelper class RssHelper(View $view.6. After a few simple steps you can simply append the desired extension . If true is passed. First parseExtensions needs to be activated. New in version 2. Release 2.

That information can also go in the view. More about Views 183 . first we need to edit the controller to add in the rss-specific code. } With all the View variables set we need to create an rss layout. Now when the address posts/index. That will come later though. $this->set(compact('posts')).x Router::parseExtensions('rss'). so deliver // data used by website's interface $this->paginate['Post'] = array( 'order' => 'Post. However. array('limit' => 20. } // this is not an Rss request. 'order' => 'Post.CakePHP Cookbook Documentation. This will activate each extension/content-type for use in your application. 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. When using Router::parseExtensions() you can pass as many arguments or extensions as you want. Before we can make an RSS version of our posts/index we need to get a few things in order. Controller Code It is a good idea to add RequestHandler to your PostsController’s $components array. In the call above we’ve activated the . so that should be added to the controller as well: public $helpers = array('Text'). return $this->set(compact('posts')). Release 2.created DESC') ).rss is requested you will get an xml version of your posts/index. which is the // index action in our example public function index() { if ($this->RequestHandler->isRss() ) { $posts = $this->Post->find( 'all'. This will allow a lot of automagic to occur: public $components = array('RequestHandler'). Our view will also use the TextHelper for formatting. 'limit' => 10 ).created DESC'.rss extension. 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: // Modify the Posts Controller action that corresponds to // the action which deliver the rss feed. $posts = $this->paginate().

array( 'title' => __("Most Recent Posts"). these contain all the metadata for our RSS feed. $channel). located at app/View/Posts/rss/index. } $channel = $this->Rss->channel(array(). Note: You will need to modify the $postLink variable as appropriate to your application. 184 Chapter 5. 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. echo $this->Rss->document($documentData.ctp. } if (!isset($channelData['title'])) { $channelData['title'] = $this->fetch('title'). 'description' => __("Most recent posts. } if (!isset($channelData)) { $channelData = array().ctp inside that folder. Views . This is done by using the View::set() method which is analogous to the Controller::set() method. thus not giving access to the TimeHelper or any other helper that you may need. (The method I have seen used for the callback has always been called transformRss().CakePHP Cookbook Documentation. We haven’t set $documentData or $channelData in the controller. Release 2.x Layout An Rss layout is very simple. It doesn’t look like much but thanks to the power in the RssHelper it’s doing a lot of lifting for us. The other method you can use. RssHelper::items() which takes a callback and an array of items for the feed. 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. There is one downfall to this method. $channelData.ctp: put the following contents in if (!isset($documentData)) { $documentData = array(). View Our view."). Much like the layout file we created. 'language' => 'en-us' )). The RssHelper::item() transforms the associative array into an element for each key value pair. 'link' => $this->Html->url('/'. however in CakePHP your views can pass variables back to the layout. $this->fetch('content')). we need to create a View/Posts/rss/ directory and create a new index. Next up is view file for my posts/index. true). Here though we are passing the channel’s metadata back to the layout: $this->set('channelData'. begins by setting the $documentData and $channelData variables for the layout. The contents of the file are below. foreach ($posts as $post) { $postTime = strtotime($post['Post']['created']). app/View/Layouts/rss/default. Which is where our $channelData array will come from setting all of the meta data for our feed.

x $postLink = array( 'controller' => 'posts'. $postTime).w3. 'guid' => array('url' => $postLink. Rss Helper API property RssHelper::$action Current action property RssHelper::$base Base URL property RssHelper::$data More about Views 185 .'. 'link' => $postLink. 'month' => date('m'. as they could cause validation errors. 'isPermaLink' => 'true'). $postTime). $post['Post']['slug'] ). you can test your RSS feed by going to your site /posts/index. 'description' => $bodyText. In the code above we used strip_tags() and h() to remove/escape any XML special characters from the content.CakePHP Cookbook Documentation. $bodyText = $this->Text->truncate($bodyText.. $postTime). It is important to filter out any non-plain text characters out of the description.org/feed/. 'action' => 'view'. 'pubDate' => $post['Post']['created'] )). 400. This can be done by visiting sites that validate the XML such as Feed Validator or the w3c site at http://validator. )). Once we have set up the data for the feed. It is always important that you validate your RSS feed before making it live. especially if you are using a rich text editor for the body of your blog. 'html' => true. Once you have all this setup. echo $this->Rss->item(array().rss and you will see your new feed. we can then use the RssHelper::item() method to create the XML in RSS format. 'year' => date('Y'. 'day' => date('d'. $bodyText = h(strip_tags($post['Post']['body'])). 'exact' => true. array( 'title' => $post['Post']['title']. array( 'ending' => '. because of the various debug information added automagically under higher debug settings that break XML syntax or feed validation rules. Release 2.. Note: You may need to set the value of ‘debug’ in your core configuration to 1 or to 0 to get a valid feed. } You can see above that we can use the loop to prepare the data to be transformed into XML elements. // Remove & escape any HTML to make sure the feed content will validate.

CakePHP Cookbook Documentation. boolean $endTag = true) Return type string Generates an XML element. RssHelper::elem(string $name. RssHelper::time(mixed $time) Return type string Converts a time in any format to an RSS time. RssHelper::item(array $att = array (). Views . RssHelper::channel(array $attrib = array (). Release 2. mixed $content = null) Return type string Returns an RSS <channel /> element.x POSTed model data property RssHelper::$field Name of the current field property RssHelper::$helpers Helpers used by the RSS Helper property RssHelper::$here URL to current action property RssHelper::$model Name of current model property RssHelper::$params Parameter array property RssHelper::$version Default spec version of generated RSS. See TimeHelper::toRSS(). and maps it to a set of <item /> tags. array $elements = array ()) Return type string Converts an array into an <item /> element and its contents. RssHelper::items(array $items. 186 Chapter 5. RssHelper::document(array $attrib = array (). string $content = null) Return type string Returns an RSS document wrapped in <rss /> tags. array $attrib = array (). mixed $content = null. array $elements = array (). mixed $callback = null) Return type string Transforms an array of data using an optional callback.

username. Displaying notifications or flash messages SessionHelper::flash(string $key = ‘flash’. Given the previous array structure. array $settings = array()) As a natural counterpart to the Session Component. SessionHelper::consume($name) Return type mixed Read and delete a value from the Session. SessionHelper::error() Return type string Returns last error encountered in a session.0: You should use FlashHelper to render flash messages. SessionHelper::read(string $key) Return type mixed Read from the Session. with the dot indicating the nested array.7. More about Views 187 . Returns a boolean representing the key’s existence.x SessionHelper class SessionHelper(View $view. This notation is used for all Session helper methods wherever a $key is used. array $params = array()) Deprecated since version 2. SessionHelper::valid() Return type boolean Used to check whether a session is valid in a view. 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. Returns a string or array depending on the contents of the session. the Session Helper replicates most of the component’s functionality and makes it available in your view.com' )). data is read by using dot notation array structures: array('User' => array( 'username' => 'super@example. SessionHelper::check(string $key) Return type boolean Check to see whether a key is in the Session. This is useful when you want to combine reading and deleting values in a single operation. As with the Session Component. Release 2. the node would be accessed by User.CakePHP Cookbook Documentation.

you can set additional properties and customize which element is used. you will want to display them. </div> As with the component method. // View/Elements/payment. echo $this->Session->flash('flash'. CakePHP does not escape the HTML in flash messages. you might have code like: // in a controller $this->Session->setFlash('The user could not be deleted. you can create one-time notifications for feedback. This would use View/Elements/failure.'). // In the layout. you should escape it with h when formatting your messages. array('element' => 'failure')). The failure element would contain something like this: <div class="flash flash-failure"> <?php echo h($message).ctp <div class="flash payment"> <?php printf($message. ?> </div> Note: By default.CakePHP Cookbook Documentation. If you are using any request or user data in your flash messages. you can choose the element used to display the message: // in a layout. Views . When outputting this message. After creating messages with SessionComponent::setFlash(). Once a message is displayed. it will be removed and not displayed again: echo $this->Session->flash(). The message text would be available as $message in the element. which allows you to generate customized messages: // In the controller $this->Session->setFlash('Thanks for your payment. In the controller.').x As explained in Creating notification messages. Release 2. 188 Chapter 5. ?> </div> You can also pass additional parameters into the flash() method.ctp to render the message. The above will output a simple message with the following HTML: <div id="flashMessage" class="message"> Your stuff has been saved. array( 'params' => array('name' => $user['User']['name']) 'element' => 'payment' )). h($name)). echo $this->Session->flash('flash'.

$linkedText = $this->Text->autoLinkEmails($myText).1 this method automatically escapes its input. creating excerpts of text around chosen words or phrases. • $options (array) – An array html attributes for the generated links More about Views 189 . Within a view. these methods are accessible via the TextHelper class. formatting URLs. contact <a href="mailto:info@example. Adds links to the well-formed email addresses in $text.1: In 2. array $options=array()) Parameters • $text (string) – The text to autolink.CakePHP Cookbook Documentation. • $options (array) – An array html attributes for the generated links Same as autoLinkEmails(). Use the escape option to disable this if necessary. $myText = 'For more information regarding our world-famous ' . TextHelper::autoLink(string $text. array $options=array()) Parameters • $text (string) – The text to convert. • $options (array) – An array of html attributes for the generated links. and gracefully truncating long stretches of text.1: Several TextHelper methods have been moved into the String class to allow easier use outside of the View layer. array $settings = array()) The TextHelper contains methods to make text more usable and friendly in your views. according to any options defined in $options (see HtmlHelper::link()). It aids in enabling links. TextHelper::autoLinkUrls(string $text.com</a> Changed in version 2. ftp. Changed in version 2. array $options=array()) Parameters • $text (string) – The text to convert. only this method searches for strings that start with https. Output: For more information regarding our world-famous pastries and desserts. http. Use the escape option to disable this if necessary. TextHelper::autoLinkEmails(string $text. or nntp and links them appropriately..1 this method automatically escapes its input. 'pastries and desserts.com">info@example. You can call one as you would call a normal helper method: $this->Text->method($args).1: In 2. contact info@example. Release 2. highlighting key words in blocks of text.x TextHelper class TextHelper(View $view. Changed in version 2.com'.

All URLs and emails are linked appropriately given the supplied $options. and <br> where single-line returns are found.1: As of 2. // called as CakeText 190 Chapter 5. array $options = array()) Parameters • $haystack (string) – The string to search. 'using'. ensuring that only the correct text is highlighted Example: // called as TextHelper echo $this->Text->highlight( $lastSentence.com'. see below.1.CakePHP Cookbook Documentation. will ignore any HTML tags. TextHelper::highlight(string $haystack. Use the escape option to disable this if necessary. $formattedText = $this->Text->autoParagraph($myText).<p> <p>contact info@example. Release 2. $myText = 'For more information regarding our world-famous pastries and desserts.string The piece of HTML with that the phrase will be highlighted •‘html’ .x Performs the functionality in both autoLinkUrls() and autoLinkEmails() on the supplied $text. • $needle (string) – The string to find.bool If true. Changed in version 2. Output: <p>For more information<br /> regarding our world-famous pastries and desserts. Options: •‘format’ . TextHelper::autoParagraph(string $text) Parameters • $text (string) – The text to convert. • $options (array) – An array of options.4. Adds proper <p> around text where double-line returns are found. Views . Highlights $needle in $haystack using the $options[’format’] string specified or a default string. this method automatically escapes its input. array('format' => '<span class="highlight">\1</span>') ).com</p> New in version 2. string $needle. contact info@example.

22..CakePHP Cookbook Documentation. • $length (int) – The length. TextHelper::truncate(string $text. 'Utility'). If ’exact’ is passed as false. HTML tags will be respected and will not be cut off. 'exact' => true. array( 'ellipsis' => '.. int $length=100. echo CakeText::truncate( More about Views 191 .. if defined. this method truncates it at $length and adds a prefix consisting of ’ellipsis’. 'Utility'). echo CakeText::highlight( $lastSentence.. 'exact' => false ) ).'. beyond which the text should be truncated.'. array $options) Parameters • $text (string) – The text to truncate. in characters.x App::uses('CakeText'. 'html' => false ) Example: // called as TextHelper echo $this->Text->truncate( 'The killer crept forward and tripped on the rug. TextHelper::stripLinks($text) Strips the supplied $text of any HTML links. all of which are optional: array( 'ellipsis' => '. If ’html’ is passed as true. 'using'. and has the following possible keys by default. Release 2. • $options (array) – An array of options to use. If $text is longer than $length characters. array('format' => '<span class="highlight">\1</span>') ). the truncation will occur at the first whitespace after the point at which $length is exceeded.'. $options is used to pass all extra parameters. // called as CakeText App::uses('CakeText'. Output: Highlights $needle in $haystack <span class="highlight">using</span> the $options['format'] string specified or a default string.

x 'The killer crept forward and tripped on the rug. and has the following possible keys by default. array( 'ellipsis' => '. 70.. the truncation will occur at the first whitespace prior to the point at which truncation would otherwise take place. ' . If ’exact’ is passed as false.'. 'exact' => false ) ).'. this method removes an initial substring with length consisting of the difference and prepends a suffix consisting of ’ellipsis’. • $length (int) – The length. Views . beyond which the text should be truncated. 22. all of which are optional: array( 'ellipsis' => '.. a TV. in characters.3: ending has been replaced by ellipsis.1 TextHelper::tail(string $text.2.'.. $options is used to pass all extra parameters. 'exact' => true ) New in version 2.. Example: $sampleText = 'I packed my bag and in it I put a PSP. Changed in version 2. 'exact' => false ) ). • $options (array) – An array of options to use. ending is still used in 2. If $text is longer than $length characters.. death metal t-shirts' // called as TextHelper echo $this->Text->tail( $sampleText. if defined. // called as CakeText 192 Chapter 5.CakePHP Cookbook Documentation. Release 2. Output: The killer crept. array $options) Parameters • $text (string) – The text to truncate. 'a C# program that can divide by zero.'. a PS3. int $length=100.3... array( 'ellipsis' => '..

// called as TextHelper echo $this->Text->excerpt($lastParagraph. '.. Extracts an excerpt from $haystack surrounding the $needle with a number of characters on each side determined by $radius.. 'exact' => false ) ). • $needle (string) – The string to excerpt around. '... string $ellipsis=”. and prefix/suffix with $ellipsis. $and=’and’) Parameters • $list (array) – Array of elements to combine into a list sentence. 70.. death metal t-shirts TextHelper::excerpt(string $haystack. // called as CakeText App::uses('CakeText'. and prefix/suffix with $ellipsis. echo CakeText::tail( $sampleText..... 'Utility').”) Parameters • $haystack (string) – The string to search.'). This method is especially handy for search results. by $radius. // called as TextHelper echo $this->Text->toList($colors).'. echo CakeText::excerpt($lastParagraph. Release 2. a C# program that can divide by zero. 'Utility').').a TV.. 'method'. This method is especially handy for search results. The query string or keywords can be shown within the resulting document. Output: . 50. TextHelper::toList(array $list. string $needle. The query. • $radius (int) – The number of characters on either side of $needle you want to include.. integer $radius=100. array( 'ellipsis' => '.CakePHP Cookbook Documentation. 50. Output: .. 'method'. More about Views 193 .x App::uses('CakeText'. Creates a comma-separated list where the last two items are joined with ‘and’. • $ellipsis (string) – Text to append/prepend to the beginning or end of the result... • $and (string) – The word used for the last join.

in app/Config/core. Now that we know the time zone of the logged in user we can correct the date and time on our posts using the Time Helper: echo $this->Time->format( 'F jS. The $timezone parameter accepts a valid timezone identifier string or an instance of DateTimeZone class. Lets use a forum as an example. yellow. indigo and violet TimeHelper class TimeHelper(View $view.CakePHP Cookbook Documentation. orange. echo CakeText::toList($colors). Changed in version 2. 2011 03:53 PM for a user in GMT-8 // and August 23rd. sorry). blue. these methods are accessible via the TimeHelper class and you can call it as you would call a normal helper method: $this->Time->method($args). 'Utility'). Uncomment the line date_default_timezone_set(’UTC’). $post['Post']['created']. null. Views . Release 2. It can format time strings.x // called as CakeText App::uses('CakeText'. Next add a time zone field to your users table and make the necessary modifications to allow your users to set their time zone. It can test time (but cannot bend time. Output: red. 2011 11:53 PM for a user in GMT+0 // August 22nd. $user['User']['time_zone'] ). It allows for the quick processing of time related information. 2011 09:53 AM GMT+10 Most of the Time Helper methods have a $timezone parameter. An easy way to manage the time is to save all dates and times as GMT+0 or UTC. array $settings = array()) The Time Helper does what it says on the tin: saves you time.1: TimeHelper has been refactored into the CakeTime class to allow easier use outside of the View layer. Your forum has many users who may post messages at any time from any part of the world. 2. green. Using the Helper A common use of the Time Helper is to offset the date and time to match a user’s time zone. The Time Helper has two main tasks that it can perform: 1.. // Will display August 22nd. Y h:i A'. Within a view. 194 Chapter 5.php to ensure your application’s time zone is set to GMT+0.

2011'. 'created'). 2011'. Release 2.x Formatting TimeHelper::convert($serverTime. 'Asia/Jakarta').2: $dateString parameter now also accepts a DateTime object. $timezone = NULL) Return type string Returns a string in the format “($field_name >= ‘2008-01-21 00:00:00’) AND ($field_name <= ‘200801-25 23:59:59’)”. $time = NULL) Return type string Converts a string representing the format for the function strftime and returns a Windows safe and i18n aware format. $fieldName. given his/her timezone.2: $timezone parameter replaces $userOffset parameter used in 2. New in version 2. $field_name. // called via TimeHelper echo $this->Time->convert(time().1 and below. TimeHelper::daysAsSql($begin.2: $timezone parameter replaces $userOffset parameter used in 2. 'modified'). Changed in version 2. $end. 2011'. // 1321038036 // called as CakeTime App::uses('CakeTime'. TimeHelper::convertSpecifiers($format. 2011'. Changed in version 2. 'Utility'). // (modified >= '2011-08-22 00:00:00') AND // (modified <= '2011-08-22 23:59:59') // called as CakeTime App::uses('CakeTime'. echo CakeTime::convert(time(). 'Utility'). echo CakeTime::dayAsSql('Aug 22. new DateTimeZone('Asia/Jakarta')). This is handy if you need to search for records between two dates inclusively: // called via TimeHelper echo $this->Time->daysAsSql('Aug 22. // (created >= '2011-08-22 00:00:00') AND // (created <= '2011-08-25 23:59:59') More about Views 195 .CakePHP Cookbook Documentation. 'modified').1 and below. TimeHelper::dayAsSql($dateString. $timezone = NULL) Return type integer Converts given time (in server’s time zone) to user’s local time. 'Aug 25. $timezone = NULL) Return type string Creates a string in the same format as daysAsSql but only needs a single date object: // called via TimeHelper echo $this->Time->dayAsSql('Aug 22.

1 and below. 'Aug 25. You can also provide the date/time as the first argument. 5 6 http://www.2: $format and $date parameters are in opposite order as used in 2.php.2: $date parameter now also accepts a DateTime object.strftime. 'Utility'). $timezone = NULL) Return type string Will return a string formatted to the given format using the PHP strftime() formatting options5 : // called via TimeHelper echo $this->Time->format('2011-08-22 11:53:00'. TimeHelper::format($date. echo CakeTime::format('2011-08-22'. Changed in version 2. Views . echo CakeTime::format('+2 days'. 'created').1 and below. // August 22. 2011 11:53 AM echo $this->Time->format('+2 days'. $timezone parameter replaces $userOffset parameter used in 2. TimeHelper::fromString($dateString. // called as CakeTime App::uses('CakeTime'.1 and below. echo CakeTime::format('2011-08-22 11:53:00'. 'Utility').php. $default = false. %Y %H:%M %p'). 2011'). '%B %e. This call signature allows you to leverage locale aware date formatting which is not possible using date() compatible formatting: // called via TimeHelper echo $this->Time->format('2012-01-13'. '%c').2: $dateString parameter now also accepts a DateTime object. Changed in version 2. $default parameter replaces $invalid parameter used in 2. $timezone = NULL) Return type string Takes a string and uses strtotime6 to convert it into a date integer: // called via TimeHelper echo $this->Time->fromString('Aug 22. '%B %e. New in version 2.net/manual/en/function. echo CakeTime::daysAsSql('Aug 22.CakePHP Cookbook Documentation. 'invalid'). %Y %H:%M %p'). 2011'. Release 2.php 196 Chapter 5.2: $timezone parameter replaces $userOffset parameter used in 2. New in version 2. // 2 days from now formatted as Sun.1 and below. When doing this you should use strftime compatible formatting. '%d-%m-%Y'). 13 Nov 2011 03:36:10 AM EET // called as CakeTime App::uses('CakeTime'. 2011'.php http://us.x // called as CakeTime App::uses('CakeTime'. '%c'). $format = NULL. 'Utility').date.net/manual/en/function. '%d-%m-%Y'.

Aug 22nd 2011. // Mon. 2011').2: $timezone parameter replaces $userOffset parameter used in 2. Changed in version 2. given either a UNIX timestamp or a valid strtotime() date string.CakePHP Cookbook Documentation. TimeHelper::niceShort($dateString = NULL. // called via TimeHelper echo $this->Time->gmt('Aug 22. 'Utility').2: $dateString parameter now also accepts a DateTime object. New in version 2. 2011'). $timezone = NULL. 'Utility'). For more info about LC_TIME file check here. 2011'). 11:53 // called as CakeTime App::uses('CakeTime'. echo CakeTime::fromString('+1 days').2: $timezone parameter replaces $userOffset parameter used in 2. TimeHelper::gmt($dateString = NULL) Return type integer Will return the date as an integer set to Greenwich Mean Time (GMT). echo CakeTime::nice('2011-08-22 11:53:00'). $timezone = NULL) Return type string Returns a formatted date string. Release 2. echo CakeTime::gmt('Aug 22. It take in account the default date format for the current language if a LC_TIME file is used.1 and below. // 1321074066 (+1 day from current date) // called as CakeTime App::uses('CakeTime'. 'Utility'). $invalid = false. $format = null) Return type string Takes a date string and outputs it in the format “Tue. $timezone = NULL) More about Views 197 . TimeHelper::nice($dateString = NULL. 19:25” or as per optional $format param passed: // called via TimeHelper echo $this->Time->nice('2011-08-22 11:53:00'). echo CakeTime::fromString('Aug 22.1 and below.x // 1313971200 echo $this->Time->fromString('+1 days'). Changed in version 2. TimeHelper::i18nFormat($date. $format = NULL. // 1313971200 // called as CakeTime App::uses('CakeTime'. Jan 1st 2008.

3 days ago”: // called via TimeHelper echo $this->Time->timeAgoInWords('Aug 22. echo CakeTime::timeAgoInWords( 'Aug 22. Y'. the format will be “Today. echo CakeTime::niceShort('2011-08-22 11:53:00'). array('format' => 'F jS. 2011'). Changed in version 2. 'Utility'). If the date object is today. Release 2. 11:53 // called as CakeTime App::uses('CakeTime'. Y') ). 2011 echo $this->Time->timeAgoInWords( 'Aug 22. Views . 2011'. 2011'). $options = array()) Return type string 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.x Return type string Takes a date string and outputs it in the format “Jan 1st 2008. If the date object is yesterday. 19:25”: // called via TimeHelper echo $this->Time->niceShort('2011-08-22 11:53:00'). 198 Chapter 5. // on 22/8/11 // on August 22nd.CakePHP Cookbook Documentation. Use the ‘end’ option to determine the cutoff point to no longer will use words. New in version 2. array('format' => 'F jS. echo CakeTime::timeAgoInWords('Aug 22. TimeHelper::timeAgoInWords($dateString. 2011'. “3 weeks. 2011'.2: $dateString parameter now also accepts a DateTime object. default ‘+1 month’: // called via TimeHelper echo $this->Time->timeAgoInWords( 'Aug 22. 'Utility'). TimeHelper::serverOffset() Return type integer Returns server’s offset from GMT in seconds. // Aug 22nd. 19:25”. array('format' => 'F jS. // called as CakeTime App::uses('CakeTime'. 'end' => '+1 year') ).1 and below. the format will be “Yesterday.2: $timezone parameter replaces $userOffset parameter used in 2. Y') ). 19:25”.

5 days and 6 hours ago echo CakeTime::timeAgoInWords($timestamp. Y'. true). New in version 2. 3 or 4 depending on what quarter of the year the date falls in. 2011'. Use the ‘accuracy’ option to determine how precise the output should be. // Outputs '1 month ago' Changed in version 2.x // On Nov 10th. /* Array ( [0] => 2011-07-01 [1] => 2011-09-30 ) */ // called as CakeTime App::uses('CakeTime'. If range is set to true. $timezone = NULL) Return type string Will return a date string in the Atom format “2008-01-12T00:00:00Z” Changed in version 2. 2011'). New in version 2. 2 weeks. 2011'. 2011 it would display: 2 months.2: $dateString parameter now also accepts a DateTime object. 'end' => '1 year' )). 'end' => '+1 year') ).1 and below. Release 2. 6 days ago // called as CakeTime App::uses('CakeTime'. 1 week. 'Utility'). 2.2: $dateString parameter now also accepts a DateTime object. a two element array will be returned with start and end dates in the format “2008-03-31”: // called via TimeHelper echo $this->Time->toQuarter('Aug 22. $range = false) Return type mixed Will return 1. TimeHelper::toAtom($dateString. More about Views 199 .CakePHP Cookbook Documentation. You can use this to limit the output: // If $timestamp is 1 month.2: $timezone parameter replaces $userOffset parameter used in 2.2: The accuracy option was added. 'Utility'). array( 'accuracy' => array('month' => 'month'). TimeHelper::toQuarter($dateString. array('format' => 'F jS. // Would print 3 $arr = $this->Time->toQuarter('Aug 22. echo CakeTime::timeAgoInWords( 'Aug 22.

CakePHP Cookbook Documentation. Testing Time TimeHelper::isToday($dateString. Changed in version 2. TimeHelper::toServer($dateString. before. TimeHelper::listTimezones($filter = null. $country = null. New in version 2. abbr. Views . TimeHelper::toUnix($dateString. Specify abbr => true will append the timezone abbreviation in the <option> text. and after keys. $timezone = NULL) Return type string Will return a date string in the RSS format “Sat. $timezone = NULL.2: $timezone parameter replaces $userOffset parameter used in 2. Release 2. TimeHelper::toRSS($dateString.timezone’ configuration variable.2: Returns a formatted date in server’s timezone.4: The new option parameters relativeString (defaults to %s ago) and absoluteString (defaults to on %s) to allow customization of the resulting output string are now available. 2011'. New in version 2.2: Returns a list of timezone identifiers.2: $timezone parameter replaces $userOffset parameter used in 2. Changed in version 2. $timezone = NULL) Return type integer A wrapper for fromString.2: Returns a timezone object from a string or the user’s timezone object.2: $dateString parameter now also accepts a DateTime object.1 and below. If the function is called without a parameter it tries to get timezone from ‘Config. true). 2011'). $arr = CakeTime::toQuarter('Aug 22.2: $dateString parameter now also accepts a DateTime object. New in version 2.2: $dateString parameter now also accepts a DateTime object. $timezone = NULL) 200 Chapter 5.8: $options now accepts array with group. 12 Jan 2008 00:00:00 -0500” Changed in version 2. TimeHelper::timezone($timezone = NULL) Return type DateTimeZone New in version 2. $options = array()) Return type array New in version 2. New in version 2.x echo CakeTime::toQuarter('Aug 22.1 and below. $format = ‘Y-m-d H:i:s’) Return type mixed New in version 2.

} You can also add helpers from within an action. To enable a helper in your view.4. 'Time').Comment'). $dateString. $timezone = NULL) TimeHelper::isThisYear($dateString. $timezone = NULL) TimeHelper::isThisMonth($dateString. 'Html'. $timezone = NULL) TimeHelper::wasYesterday($dateString.4.2: $timezone parameter replaces $userOffset parameter used in 2. If a time interval is not recognized (for example.2: $dateString parameter now also accepts a DateTime object. This saves processing power for the other actions that do not use the helper and helps keep the controller better organized: More about Views 201 . } Adding helpers from plugins uses the plugin syntax used elsewhere in CakePHP: class BakeriesController extends AppController { public $helpers = array('Blog. wasWithinLast takes a time interval which is a string in the format “3 months” and accepts a time interval of seconds. $dateString). add the name of the helper to the controller’s $helpers array: class BakeriesController extends AppController { public $helpers = array('Form'. $timezone = NULL) Changed in version 2. Using and Configuring Helpers You enable helpers in CakePHP by making a controller aware of them. $dateString). All of the above functions return true or false when passed a date string. $timezone = NULL) TimeHelper::isFuture($dateString. months and years (plural and not). CakeTime::wasWithinLast($timeInterval. wasWithinLast takes an additional $timeInterval option: // called via TimeHelper $this->Time->wasWithinLast($timeInterval.1 and below. weeks. hours.x TimeHelper::isThisWeek($dateString. TimeHelper::wasWithinLast($timeInterval.CakePHP Cookbook Documentation. 'Utility'). // called as CakeTime App::uses('CakeTime'. TimeHelper::isPast($dateString. Release 2. minutes. days. $timezone = NULL) New in version 2. New in version 2. if it is mistyped) then it will default to days. 'Js'. $timezone = NULL) TimeHelper::isTomorrow($dateString. $timezone = NULL) New in version 2. so they will only be available to that action and not to the other actions in the controller. Each controller has a $helpers property that lists the helpers to be made available in the view.

x class BakeriesController extends AppController { public function bake() { $this->helpers[] = 'Time'. 202 Chapter 5.3.php App::uses('HtmlHelper'. 'Js'. which allows you to create aliased helpers in your views. add the name of the helper to the $helpers array in /app/Controller/AppController. } // app/View/Helper/MyHtmlHelper. These options can be used to set attribute values or modify behavior of a helper: class AwesomeHelper extends AppHelper { public function __construct(View $view. Release 2. 'Html'. debug($settings).php (or create it if not present). the options are merged with the Helper::$settings property of the helper. Remember to include the default Html and Form helpers: class AppController extends Controller { public $helpers = array('Form'. This feature is useful when you want to replace $this->Html or another common Helper reference with a custom implementation: // app/Controller/PostsController. 'View/Helper'). Views .php class PostsController extends AppController { public $helpers = array( 'Html' => array( 'className' => 'MyHtml' ) ). class MyHtmlHelper extends HtmlHelper { // Add your code to override the core HtmlHelper } The above would alias MyHtmlHelper to $this->Html in your views. } public function mix() { // The Time helper is not loaded here and thus not available } } If you need to enable a helper for all controllers. $settings).CakePHP Cookbook Documentation. 'Time'). One common setting to use is the className option. $settings = array()) { parent::__construct($view. } } class AwesomeController extends AppController { public $helpers = array('Awesome' => array('option1' => 'value1')). } As of 2. } You can pass options to helpers.

$url) { More about Views 203 . $mediaSettings). Release 2. you can set those in your controller’s beforeRender callback: class PostsController extends AppController { public function beforeRender() { parent::beforeRender(). The HelperCollection is a collection and supports the collection API used elsewhere in CakePHP. Let’s say we wanted to create a helper that could be used to output a specifically crafted CSS-styled link you needed many different places in your application. If you have configuration options that cannot be included as part of a class declaration. $this->helpers['CustomStuff'] = $this->_getCustomStuffSettings(). class LinkHelper extends AppHelper { public function makeEdit($title. } } Using Helpers Once you’ve configured which helpers you want to use in your controller.x Note: Aliasing a helper replaces that instance anywhere that helper is used. Creating Helpers If a core helper (or one showcased on GitHub or in the Bakery) doesn’t fit your needs.CakePHP Cookbook Documentation. The above would call the css method on the HtmlHelper. Let’s call our helper LinkHelper. Using helper settings allows you to declaratively configure your helpers and keep configuration logic out of your controller actions. 'View/Helper'). including inside other Helpers. In order to fit your logic into CakePHP’s existing helper structure. You can use the view’s HelperCollection to do this: $mediaHelper = $this->Helpers->load('Media'.php */ App::uses('AppHelper'. The actual PHP class file would look something like this: /* /app/View/Helper/LinkHelper. Callback methods Helpers feature several callbacks that allow you to augment the view rendering process. You can access any loaded helper using $this->{$helperName}. See the Helper API and the Collections documentation for more information. helpers are easy to create. you’ll need to create a new class in /app/View/Helper. if you were using the HtmlHelper you would be able to access it by doing the following: echo $this->Html->css('styles'). There may come a time where you need to dynamically load a helper from inside a view. each helper is exposed as a public property in the view. For example.

formatted just as you would in a controller: /* /app/View/Helper/LinkHelper. you’ll be able to include it in your controllers using the special variable $helpers: class PostsController extends AppController { public $helpers = array('Link'). To do so. $url. Views . create /app/View/Helper/AppHelper. $url) { // Use the HTML helper to output // formatted data: $link = $this->Html->link($title. array('class' => 'edit')). '/recipes/edit/5'). To create functionality that would be available to all helpers.php: 204 Chapter 5. ?> Creating Functionality for All Helpers All helpers extend a special class. } Once your controller has been made aware of this new class.make a link using the new helper --> <?php echo $this->Link->makeEdit('Change this Recipe'.CakePHP Cookbook Documentation. $link . public function makeEdit($title. Including other Helpers You may wish to use some functionality already existing in another helper.php (using other helpers) */ App::uses('AppHelper'.. 'View/Helper'). return '<div class="editOuter">' . class LinkHelper extends AppHelper { public $helpers = array('Html'). } } Using your Helper Once you’ve created your helper and placed it in /app/View/Helper/. '</div>'.x // Logic to create specially formatted link goes here. you can use it in your views by accessing an object named after the helper: <!-.. you can specify helpers you wish to use with a $helpers array. Release 2. AppHelper (just like models extend AppModel and controllers extend AppController). } } Note: Helpers must extend either AppHelper or Helper or implement all the callbacks in the Helper API.

'View'). $field = null. This includes elements. Helper::afterRenderFile($viewFile. Release 2. class AppHelper extends Helper { public function customMethod() { } } Helper API class Helper The base class for Helpers. Helper::value($options = array(). $full = false) Generates an HTML escaped URL. It provides a number of utility methods and features for loading other helpers. This includes elements. $content) Is called after each view file is rendered. Helper::webroot($file) Resolve a file name to the webroot of the application. $id = ‘id’) Generate a CamelCased id value for the currently selected field. delegates to Router::url(). Overriding this method in your AppHelper will allow you to change how CakePHP generates ID attributes. $key = ‘value’) Get the value for a given input name. Helper::beforeRender($viewFile) The beforeRender method is called after the controller’s beforeRender method but before the controller renders view and layout. parent views and layouts. Receives the layout filename as an argument.x App::uses('Helper'. Receives the file being rendered as an argument. parent views and layouts. Callbacks Helper::beforeRenderFile($viewFile) Is called before each view file is rendered. Helper::afterRender($viewFile) Is called after the view has been rendered but before layout rendering has started. Helper::beforeLayout($layoutFile) Is called before layout rendering starts. views. Helper::afterLayout($layoutFile) Is called after layout rendering is complete. the path to the themed file will be returned. A callback can modify and return $content to change how the rendered content will be displayed in the browser. If a theme is active and the file exists in the current theme’s webroot. More about Views 205 .CakePHP Cookbook Documentation. Helper::url($url. Helper::domId($options = null. Receives the layout filename as an argument. views.

x 206 Chapter 5.CakePHP Cookbook Documentation. Release 2. Views .

may have many blog posts and each blog post may have many comments. For example. a Recipe may be associated with an Author as well as an Ingredient. model classes represent data and are used in CakePHP applications for data access. It will describe how to find. They generally represent a database table but can be used to access anything that manipulates data such as files. They should be responsible for managing almost everything regarding your data. it will look at Datasources. and Comment are all examples of models. a person. a data model is an object that represents a thing such as a car. The Ingredient model extends the application model. It will explain the different ways to build associations for your data. as well as the evolution of the information workflow in your domain. The Blog. 'Model'). save. or iCal events. AppModel. and delete data. } With just this simple declaration. Post.CHAPTER 6 Models Models are the classes that form the business layer in your application. for example. Finally. A blog. This section will explain what features of the model can be automated. Usually. its validity. Understanding Models A Model represents your data model. A model can be associated with other models. the Ingredient model is endowed with all the functionality you need to create queries and to save and delete data. each associated with another. which in turn extends 207 . Here is a simple example of a model definition in CakePHP: App::uses('AppModel'. and what methods and properties a model can have. external web services. how to override those features. or a house. These methods come from CakePHP’s Model class by the magic of inheritance. In object-oriented programming. and its interactions. class Ingredient extends AppModel { public $name = 'Ingredient'.

To do so. } } Associated models are available through the main model. It is this core Model class that bestows the functionality onto your Ingredient model. a controller named IngredientsController will automatically initialize the Ingredient model and attach it to the controller at $this->Ingredient: class IngredientsController extends AppController { public function index() { //grab all ingredients and pass it to the view: $ingredients = $this->Ingredient->find('all'). In order to work on it. If you’re trying to use a method you’ve defined in your model.CakePHP Cookbook Documentation. you need to create your own AppModel. When your model is defined. App::uses(’AppModel’. is empty. AppModel. your application cache. it’s a sure sign that CakePHP can’t find your model and you need to check the file names. “File” cannot be used. Back to our Ingredient model. since “File” is a class that already exists in the CakePHP core. Note: Some class names are not usable for model names. CakePHP will use an instance of AppModel rather than your model file (which CakePHP assumes is missing). it is taken from the CakePHP core folder. Creating a project using Bake will automatically generate this file for you. CakePHP will automatically make the model available for access when its name matches that of the controller. return $this->findAllByMainIngredient($ingredient['Ingredient']['id']).php rather than Ingredient. take a 208 Chapter 6. $ingredients).php. it should have the same name as the class.php). } } This shows how to use models that are already linked. See also Behaviors for more information on how to apply similar logic to multiple models. For example. create the PHP file in the /app/Model/ directory. This also means that if your model file isn’t named correctly (for instance.x CakePHP’s internal Model class. The intermediate class. For instance. ’Model’) ensures that the model is loaded when it is needed.php or Ingredients.php file that resides in the Model folder. or both. Recipe has an association with the Ingredient model: class Recipe extends AppModel { public function steakRecipes() { $ingredient = $this->Ingredient->findByName('Steak'). or a behavior attached to your model. Note: CakePHP will dynamically create a model object for you if it cannot find a corresponding file in /app/Model. which for this example will be Ingredient. and you’re getting SQL errors that are the name of the method you’re calling. By convention. Models . In the following example. $this->set('ingredients'. it can be accessed from within your Controller. To understand how associations are defined. If you haven’t created your own. Overriding the AppModel allows you to define functionality that should be made available to all models within your application. as do all other models in your application. Release 2. if it is named ingredient.

the relation type in this model is always a Model belongsTo OtherModel relation! Associations are defined by creating a class variable named after the association you are defining. many ingredients. A user can have multiple recipes. see Plugin Models. Most of what this section covers will be in that context. and hasAndBelongsToMany (HABTM). define. Defining the way these relations work allows you to access your data in an intuitive and powerful way. Recipes have. and utilize associations between models in CakePHP. 'order' => 'Recipe. To further clarify which way around the associations are defined in the models: If the table of the model contains the foreign key (other_model_id). public $hasMany = array( 'Recipe' => array( 'className' => 'Recipe'. For information on associations with Plugin models. The purpose of this section is to show you how to plan for. the links between models are handled through associations. and belong to. Relationship Types The four association types in CakePHP are: hasOne.approved' => '1'). Relationship one to one one to many many to one many to many Association Type hasOne hasMany belongsTo hasAndBelongsToMany Example A user has one profile. hasMany. For example: in a recipe database. class User extends AppModel { public $hasOne = 'Profile'.CakePHP Cookbook Documentation. While data can come from a variety of sources.created DESC' ) More on models 209 . the most common form of storage in web applications is a relational database. reviews have a single author. belongsTo. In CakePHP. and authors may have many recipes. a recipe may have many reviews. but can be as complex as a multidimensional array used to define association specifics. The class variable can sometimes be as simple as a string.x look at the Associations section More on models Associations: Linking Models Together One of the most powerful features of CakePHP is the ability to link relational mapping provided by the model. Many recipes belong to a user. 'conditions' => array('Recipe. Defining relations between different objects in your application should be a natural process. Release 2.

public $hasAndBelongsToMany = array( 'Member' => array( 'className' => 'Group'. ) ). Models . ) ). This is an identifier for the relationship. Usually.CakePHP Cookbook Documentation. aliases for each model must be unique across the app. 210 Chapter 6. ) ). Release 2. } class Group extends AppModel { public $hasMany = array( 'MyRecipe' => array( 'className' => 'Recipe'. However. public $hasAndBelongsToMany = array( 'Member' => array( 'className' => 'User'.x ). and can be anything you choose. For example. the first instance of the word ‘Recipe’ is what is termed an ‘Alias’. ) ). you will choose the same name as the class that it references. it is appropriate to have: class User extends AppModel { public $hasMany = array( 'MyRecipe' => array( 'className' => 'Recipe'. } but the following will not work well in all circumstances: class User extends AppModel { public $hasMany = array( 'MyRecipe' => array( 'className' => 'Recipe'. } In the above example. public $hasAndBelongsToMany = array( 'MemberOf' => array( 'className' => 'Group'. } class Group extends AppModel { public $hasMany = array( 'MyRecipe' => array( 'className' => 'Recipe'. ) ). ) ).

You need to define Recipe belongsTo User to be able to access the User model from your Recipe model. You can easily override the use of any foreignKey in your associations definitions.apple_id profiles. Release 2. Relation Apple hasOne Banana User hasOne Profile Doctor hasOne Mentor Schema bananas. If you define User hasMany Recipe. So for example in your User model you can access the Recipe model as: $this->Recipe->someFunction(). The User model file will be saved in /app/Model/User. public $hasAndBelongsToMany = array( 'Member' => array( 'className' => 'User'. that has no effect on the Recipe Model. or the association won’t work: More on models 211 .php. Choosing non-unique names for model aliases across models can cause unexpected behavior. hasOne Let’s set up a User model with a hasOne relationship to a Profile model. The basic pattern is: hasOne: the other model contains the foreign key.doctor_id Note: It is not mandatory to follow CakePHP conventions. First.CakePHP Cookbook Documentation.user_id mentors. Nevertheless. In this case. one table has to contain a foreign key that points to a record in the other. add the $hasOne property to the model class. To define the ‘User hasOne Profile’ association. the profiles table will contain a field called user_id. } because here we have the alias ‘Member’ referring to both the User (in Group) and the Group (in User) model in the HABTM associations. Similarly in your controller you can access an associated model simply by following your model associations: $this->User->Recipe->someFunction(). sticking to conventions will make your code less repetitive and easier to read and maintain.x ) ). Remember to have a Profile model in /app/Model/Profile. ) ). CakePHP will automatically create links between associated model objects.php. For a hasOne relationship to work. Note: Remember that associations are defined ‘one way’. your database tables need to be keyed correctly.

If you need more control. 'conditions' => array('Profile.last_name’ => ‘ASC’) • dependent: When the dependent key is set to true. Array ( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) 212 Chapter 6. find operations on the User model will also fetch a related Profile record if it exists: //Sample results from a $this->User->find() call. you can define your associations using array syntax. the className key should equal ‘Profile’. • foreignKey: the name of the foreign key found in the other model. • conditions: an array of find()-compatible conditions or SQL strings such as array(‘Profile. } There are two ways to describe this relationship in your model files. Once this association has been defined. you might want to limit the association to include only certain records. } Possible keys for hasOne association arrays include: • className: the class name of the model being associated to the current model. In the example above. For example. as we’ve done above. class User extends AppModel { public $hasOne = array( 'Profile' => array( 'className' => 'Profile'. it would default to ‘user_id’.approved’ => true) • fields: A list of fields to be retrieved when the associated model data is fetched. suffixed with ‘_id’. The simplest method is to set the $hasOne attribute to a string containing the class name of the associated model. we set it true so that deleting a User will also delete her associated Profile.published' => '1'). 'dependent' => true ) ). associated model records are also deleted. This is especially handy if you need to define multiple hasOne relationships. If you’re defining a ‘User hasOne Profile’ relationship. Models . In this case. singular name of the current model. and the model’s delete() method is called with the cascade parameter set to true.x class User extends AppModel { public $hasOne = 'Profile'. • order: an array of find()-compatible order clauses or SQL strings such as array(‘Profile.CakePHP Cookbook Documentation. Release 2. Returns all fields by default. The default value for this key is the underscored.

Release 2. let’s define a belongsTo association in the Profile model in order to get access to related User data. it belongsTo the other model(table). If you’re defining a ‘Profile belongsTo User’ relationship. More on models 213 .apple_id profiles.doctor_id Tip: If a model(table) contains a foreign key.CakePHP Cookbook Documentation. } Possible keys for belongsTo association arrays include: • className: the class name of the model being associated to the current model. follow this convention: belongsTo: the current model contains the foreign key.x [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ) ) belongsTo Now that we have Profile data access from the User model. We can define the belongsTo association in our Profile model at /app/Model/Profile.user_id mentors. the className key should equal ‘User’.php using the string syntax as follows: class Profile extends AppModel { public $belongsTo = 'User'. 'foreignKey' => 'user_id' ) ). • foreignKey: the name of the foreign key found in the current model. Relation Banana belongsTo Apple Profile belongsTo User Mentor belongsTo Doctor Schema bananas. singular name of the other model. } We can also define a more specific relationship using array syntax: class Profile extends AppModel { public $belongsTo = array( 'User' => array( 'className' => 'User'. This is especially handy if you need to define multiple belongsTo relationships. The belongsTo association is a natural complement to the hasOne and hasMany associations: it allows us to see the data from the other direction. When keying your database tables for a belongsTo relationship. suffixed with _id. The default value for this key is the underscored.

then it’s the field name to use. The value ‘INNER’ may be helpful (when used with some conditions) when you want everything from your main and associated models or nothing at all. Once this association has been defined. • fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default. the model itself tracks any addition/deletion towards the associated $hasMany model and increases/decreases a dedicated integer field within the parent model table.active’ => true) conditions or SQL strings such as • type: the type of the join to use in the SQL query. You can also specify multiple counter caches by defining an array. The default is ‘LEFT’.Cache your count() This feature helps you cache the count of related data. Release 2. • counterScope: Optional conditions array to use for updating counter cache field. The name of the field consists of the singular model name followed by a underscore and the word “count”: my_model_count 214 Chapter 6. Array ( [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ) [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) ) counterCache . which may not fit your needs in all situations. Models . The value in the counter field represents the number of related rows.CakePHP Cookbook Documentation. If it’s a string.username’ => ’ASC’) order clauses or SQL strings such as • counterCache: If set to true.x • conditions: an array of find() compatible array(’User. the associated Model will automatically increase or decrease the “[singular_model_name]_count” field in the foreign table whenever you do a save() or delete(). See Multiple counterCache. find operations on the Profile model will also fetch a related User record if it exists: //Sample results from a $this->Profile->find() call. • order: an array of find() compatible array(’User. Instead of counting the records manually via find(’count’).

) ). //custom field name // only count if "ImageComment" is active = 1 'counterScope' => array( 'ImageComment. It is also possible to define a counterScope for each counterCache. Activate counter-cache in your association by adding a counterCache key and set the value to true: class ImageComment extends AppModel { public $belongsTo = array( 'Image' => array( 'counterCache' => true. You would add a new INT-field to the images table and name it image_comment_count.image_count images.active' => 1 ) ) ). depending on how you look at it) the counter value. Release 2. and you want to be able to count the amount of read and unread messages for each user.0. you are good to go. Assuming you have a User model and a Message model.CakePHP Cookbook Documentation. CakePHP has supported having multiple counterCache in a single model relation. counterScope You can also specify counterScope. Using our Image model example. Here are some more examples: Model User Image BlogEntry Associated Model Image ImageComment BlogEntryComment Example users. every time you add or remove a ImageComment associated to Image.x Let’s say you have a model called ImageComment and a model called Image.blog_entry_comment_count Once you have added the counter field. It allows you to specify a simple condition which tells the model when to update (or when not to. More on models 215 . we can specify it like so: class ImageComment extends AppModel { public $belongsTo = array( 'Image' => array( 'counterCache' => 'active_comment_count'. } Multiple counterCache Since 2. the number within image_comment_count is adjusted automatically.image_comment_count blog_entries. } From now on.

is_read' => 1).CakePHP Cookbook Documentation. } hasMany Next step: defining a “User hasMany Comment” association.user_id Virtue.created DESC'. A hasMany association will allow us to fetch a user’s comments when we fetch a User record.php using the string syntax as follows: class User extends AppModel { public $hasMany = 'Comment'. 'order' => 'Comment.is_read Description Count read Message Count unread Message Determines if a Message is read or not. your belongsTo would look like this: class Message extends AppModel { public $belongsTo = array( 'User' => array( 'counterCache' => array( 'messages_read' => array('Message. When keying your database tables for a hasMany relationship.product_id We can define the hasMany association in our User model at /app/Model/User.status' => '1'). } We can also define a more specific relationship using array syntax: class User extends AppModel { public $hasMany = array( 'Comment' => array( 'className' => 'Comment'. Release 2. } 216 Chapter 6.cake_id Option. 'foreignKey' => 'user_id'. follow this convention: hasMany: the other model contains the foreign key. 'dependent' => true ) ). 'conditions' => array('Comment. 'limit' => '5'.is_read' => 0) ) ) ). 'messages_unread' => array('Message.x Model User User Message Field users.messages_read users. Relation User hasMany Comment Cake hasMany Virtue Product hasMany Option Schema Comment. With this setup.messages_unread messages. Models .

• exclusive: When exclusive is set to true.last_name’ => ‘ASC’) • limit: The maximum number of associated rows you want returned. Release 2. the className key should equal ‘Comment.apple_id = {$__cakeID__$}. use the special {$__cakeID__$} marker in the query. singular name of the actual model. • finderQuery: A complete SQL query CakePHP can use to fetch associated model records. Comment records will be deleted when their associated User record has been deleted. This should be used in situations that require highly customized results. For example. but may not be ideal for all circumstances.x Possible keys for hasMany association arrays include: • className: the class name of the model being associated to the current model. • dependent: When dependent is set to true. Once this association has been defined. the query should look something like this: SELECT Orange.* from oranges as Orange WHERE Orange.visible’ => true) • order: an array of find() compatible order clauses or SQL strings such as array(‘Profile.CakePHP Cookbook Documentation. This is especially handy if you need to define multiple hasMany relationships. instead of deleting each entity separately. If you’re defining a ‘User hasMany Comment’ relationship. The default value for this key is the underscored. if your Apple model hasMany Orange. recursive model deletion is possible. suffixed with ‘_id’. recursive model deletion does the delete with a deleteAll() call. find operations on the User model will also fetch related Comment records if they exist: //Sample results from a $this->User->find() call. Array ( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) [Comment] => Array ( [0] => Array ( [id] => 123 [user_id] => 121 [title] => On Gwoo the Kungwoo [body] => The Kungwooness is not so Gwooish More on models 217 . If a query you’re building requires a reference to the associated model ID. In this example.’ • foreignKey: the name of the foreign key found in the other model. • conditions: an array of find() compatible conditions or SQL strings such as array(‘Comment. • offset: The number of associated rows to skip over (given the current conditions and order) before fetching and associating. This greatly improves performance.

For example. You’re already well versed in the three associations that take up the bulk of object relations. This new join table’s name needs to include the names of both models involved. in many different ways. you can define one.x [created] => 2006-05-01 10:31:01 ) [1] => Array ( [id] => 124 [user_id] => 121 [title] => More on Gwoo [body] => But what of the 'Nut? [created] => 2006-05-01 10:41:01 ) ) ) One thing to remember is that you’ll need a complementary Comment belongsTo User association in order to get the data from both directions. Relationship Recipe HABTM Ingredient Cake HABTM Fan Foo HABTM Bar HABTM Table Fields ingredients_recipes. cakes_fans.ingredient_id. and separated with an underscore ( _ ). completing the connection and allowing the flow of information from either model’s perspective. What we’ve outlined in this section empowers you to get Comment data from the User.CakePHP Cookbook Documentation.fan_id bars_foos. The main difference between hasMany and HABTM is that a link between models in HABTM is not exclusive. Moving on. repeatedly. Using tomatoes as an Ingredient for my grandma’s spaghetti recipe doesn’t “use up” the ingredient.recipe_id cakes_fans.bar_id Note: Table names are in alphabetical order by convention. I can also use it for a salad Recipe.id. ingredients_recipes. At this point. Release 2. Let’s tackle the final relationship type: hasAndBelongsToMany.id. don’t define a combined primary key for these two fields. It’s not up for grabs. bars_foos.foo_id. in alphabetical order. many times. The contents of the table should be two fields that are foreign keys (which should be integers) pointing to the primary keys of the involved models. Adding the Comment belongsTo User association in the Comment model enables you to get User data from the Comment model. cakes_fans. If your application requires a unique index. we’re about to join up our Recipe model with an Ingredient model using HABTM. you should add an additional primary key field (by convention ‘id’).id. HABTM requires a separate join table that includes both model names. Models . Links between hasMany associated objects are exclusive. bars_foos. a comment is only linked to a specific user. To avoid any issues. ingredients_recipes. This association is used when you have two models that need to be joined up.cake_id. If my User hasMany Comments. or HABTM. If you plan to add any extra information to this table. hasAndBelongsToMany (HABTM) All right. We’ll need to set up an extra table in the database to handle HABTM associations. you can already call yourself a CakePHP model associations professional. It is possible to define a custom table name in 218 Chapter 6. or use a ‘with’ model.

• unique: boolean or string keepExisting. Existing associations need to be passed again when More on models 219 . 'foreignKey' => 'recipe_id'.x association definition. Using the example above it would be called IngredientsRecipe. they must be changed in model’s primaryKey. The default value for this key is the underscored. singular name of the other model. 'order' => ''. 'fields' => ''. If they’re different than assumed. 'with' => '' ) ). • associationForeignKey: the name of the foreign key found in the other model. 'associationForeignKey' => 'ingredient_id'. 'unique' => true. 'joinTable' => 'ingredients_recipes'. The default value for this key is the underscored. 'conditions' => ''. Release 2. • foreignKey: the name of the foreign key found in the current model. 'limit' => ''. We’re going to skip straight to the array syntax this time: class Recipe extends AppModel { public $hasAndBelongsToMany = array( 'Ingredient' => array( 'className' => 'Ingredient'. the className key should equal ‘Ingredient’. – If true (default value) CakePHP will first delete existing relationship records in the foreign keys table before inserting new ones. } Possible keys for HABTM association arrays include: • className: the class name of the model being associated to the current model. • joinTable: The name of the join table used in this association (if the current table doesn’t adhere to the naming convention for HABTM join tables). suffixed with ‘_id’. The join table model can be used just like any “regular” model to access the join table directly. 'finderQuery' => ''.CakePHP Cookbook Documentation. 'offset' => ''. This is especially handy if you need to define multiple HABTM relationships. singular name of the current model. such as adding more information/columns to it. • with: Defines the name of the model for the join table. If you’re defining a ‘Recipe HABTM Ingredient’ relationship. By using this key you can override this default name. By default CakePHP will auto-create a model for you. we can define the HABTM association in the model files. Make sure primary keys in tables cakes and recipes have “id” fields as assumed by convention. Once this new table has been created. suffixed with ‘_id’. By creating a model class with such name and filename. you can add any custom behavior to the join table searches. This is especially handy if you need to define multiple HABTM relationships.

Once this association has been defined. Models . – When set to keepExisting. Returns all fields by default. This should be used in situations that require highly customized results. • order: an array of find()-compatible order clauses or SQL strings • limit: The maximum number of associated rows you want returned. find operations on the Recipe model will also fetch related Tag records if they exist: // Sample results from a $this->Recipe->find() call. for example. you should use a ‘with’ model. the join table has additional data in it that needs to be retained. This can be useful if. Array ( [Recipe] => Array ( [id] => 2745 [name] => Chocolate Frosted Sugar Bombs [created] => 2007-05-01 10:31:01 [user_id] => 2346 ) [Ingredient] => Array ( [0] => Array ( [id] => 123 [name] => Chocolate ) [1] => Array ( [id] => 124 [name] => Sugar ) [2] => Array ( 220 Chapter 6. possibly resulting in duplicate relationship records. • finderQuery: A complete SQL query CakePHP can use to fetch associated model records. and define the necessary belongsTo associations on it. the existing relationship record is not deleted. • offset: The number of associated rows to skip over (given the current conditions and order) before fetching and associating. the behavior is similar to true. but with an additional check so that if any of the records to be added are duplicates of an existing relationship record. and the duplicate is ignored. – When false.CakePHP Cookbook Documentation.x updating. If you have conditions on an associated table. Release 2. CakePHP will insert the specified new relationship records and leave any existing relationship records in place. • conditions: an array of find()-compatible conditions or SQL string. • fields: A list of fields to be retrieved when the associated model data is fetched.

the association is deleted first. See unique key in HABTM association arrays. The way to implement our requirement is to use a join model. see hasMany through (The Join Model).php class Student extends AppModel { public $hasMany = array( 'CourseMembership' ). Consider the following Student hasAndBelongsToMany Course Course hasAndBelongsToMany Student In other words. This is a simple many-to-many association demanding a table such as this: id | student_id | course_id Now what if we want to store the number of days that were attended by the student on the course and their final grade? The table we’d want would be: id | student_id | course_id | days_attended | grade The trouble is. Tip: For more information on saving HABTM objects. Each time a new data association is added. otherwise known as a hasMany through association. So. the complete set of associated rows in the database is dropped and created again so you will always need to pass the whole data set for saving. Changed in version 2. Release 2.x [id] => 125 [name] => Bombs ) ) ) Remember to define a HABTM association in the Ingredient model if you’d like to fetch Recipe data when using the Ingredient model. hasAndBelongsToMany will not support this type of scenario because when hasAndBelongsToMany associations are saved.CakePHP Cookbook Documentation. // Student. You would lose the extra data in the columns as it is not replaced in the new insert. the association is a model itself. we can create a new model CourseMembership. see Saving Related Model Data (HABTM) hasMany through (The Join Model) It is sometimes desirable to store additional data with a many-to-many association.1. That is. Take a look at the following models. More on models 221 . For an alternative to using HABTM. a Student can take many Courses and a Course can be taken by many Students. You can set the unique setting to keepExisting to circumvent losing extra data during the save operation. Note: HABTM data is treated like a complete set.

) Let’s set up a few models so we can see how bindModel() and unbindModel() work.php class CourseMembership extends AppModel { public $belongsTo = array( 'Student'. This association creation and destruction is done using the CakePHP model bindModel() and unbindModel() methods. 'Course' ). } // CourseMembership.rank' ) ). Creating and Destroying Associations on the Fly Sometimes it becomes necessary to create and destroy model associations on the fly. Release 2. } 222 Chapter 6. • You want to change the way an association is defined in order to sort or filter associated data. We’ll start with two models: class Leader extends AppModel { public $hasMany = array( 'Follower' => array( 'className' => 'Follower'. Join models are pretty useful things to be able to use. but all your associations are on the first level of recursion.php class Course extends AppModel { public $hasMany = array( 'CourseMembership' ).x } // Course. (There is also a very helpful behavior called “Containable”. This may be for any number of reasons: • You want to reduce the amount of associated data fetched. Please refer to the manual section about Built-in behaviors for more information. Models .CakePHP Cookbook Documentation. } class Follower extends AppModel { public $name = 'Follower'. and CakePHP makes it easy to do so with its built-in hasMany and belongsTo associations and saveAll feature. } The CourseMembership join model uniquely identifies a given Student’s participation on a Course in addition to extra meta-information. 'order' => 'Follower.

the association array in the Leader model defines a “Leader hasMany Followers” relationship. Release 2.php model file. the bind remains in place for the remainder of the request.. // NOTE: unbindModel only affects the very next // find function. in the LeadersController. Our as-of-yet unprincipled Leader needs some associated Principles.x Now. $this->Leader->find('all'). $this->Leader->unbindModel( array('hasMany' => array('Follower')) ). only for the following find operation).. As you can see above. // so this will fetch Leaders with associated // Followers once again. // Let's use bindModel() to add a new association // to the Leader model: $this->Leader->bindModel( More on models 223 . // Now using a find function will return // Leaders. let’s use unbindModel() to remove that association in a controller action: public function some_action() { // This fetches Leaders. we can use the find() method in the Leader model to fetch a Leader and its associated followers. Now that we’ve successfully removed an association on the fly. $this->Leader->find('all').. This function appears in the LeadersController: public function another_action() { // There is no Leader hasMany Principles in // the leader. Let’s associate some Principles to our Leader on the fly (but remember. An additional find call will use // the configured association information. so a find here // only fetches Leaders.. The model file for our Principle model is bare.CakePHP Cookbook Documentation. and their associated Followers $this->Leader->find('all'). // We've already used find('all') after unbindModel(). Here’s the basic usage pattern for unbindModel(): $this->Model->unbindModel( array('associationType' => array('associatedModelClassName')) ). let’s add one. For demonstration purposes. If the second parameter has been set to false. with no Followers $this->Leader->find('all').and unbindModel() only works for the next find operation unless the second parameter has been set to false. } Note: Removing or adding associations using bind. except for the public $name statement. // Let's remove the hasMany.

The basic usage for bindModel() is the encapsulation of a normal association array inside an array whose key is named after the type of association you are trying to create: $this->Model->bindModel( array('associationName' => array( 'associatedModelClassName' => array( // normal association keys go here. Multiple relations to the same model There are cases where a Model has more than one relation to another Model. // If we need keep this association after model reset // we will pass a second boolean parameter like this: $this->Leader->bindModel( array('hasMany' => array( 'Principle' => array( 'className' => 'Principle' ) ) ). // Now that we're associated correctly. 224 Chapter 6.. it will still need to be correctly keyed in order for the new association to work properly. but also a field recipient_id.. and a second to the user who receives the message.x array('hasMany' => array( 'Principle' => array( 'className' => 'Principle' ) ) ) ). you might have a Message model that has two relations to the User model: one relation to the user who sends a message. Models . // we can use a single find function to fetch // Leaders with their associated principles: $this->Leader->find('all'). } There you have it. For example. Release 2. Now your Message model can look something like: class Message extends AppModel { public $belongsTo = array( 'Sender' => array( 'className' => 'User'. false ). Even though the newly bound model doesn’t need any sort of association definition in its model file.CakePHP Cookbook Documentation. The messages table will have a field user_id. ) ) ) ).

'foreignKey' => 'parent_id' ) ). } Recipient is an alias for the User model. Release 2.x 'foreignKey' => 'user_id' ). } It is also possible to create self associations as shown below: class Post extends AppModel { public $belongsTo = array( 'Parent' => array( 'className' => 'Post'. 'foreignKey' => 'recipient_id' ) ). This allows you to perform complex searches across multiple tables (for example. 'MessageReceived' => array( 'className' => 'Message'. you can combine related tables using the JOIN statement. More on models 225 . public $hasMany = array( 'Children' => array( 'className' => 'Post'. } Fetching a nested array of associated records: If your table has a parent_id field. search posts given several tags). you can also use find(‘threaded’) to fetch a nested array of records using a single query without setting up any associations. 'Recipient' => array( 'className' => 'User'.CakePHP Cookbook Documentation. 'foreignKey' => 'recipient_id' ) ). Now let’s see what the User model would look like: class User extends AppModel { public $hasMany = array( 'MessageSent' => array( 'className' => 'Message'. Joining tables In SQL. 'foreignKey' => 'user_id' ). 'foreignKey' => 'parent_id' ) ).

With joins. you need to use the “modern” syntax for Model::find(). You can alias the table with the Model name. a model called Item is left-joined to the channels table. $Item->find('all'. so the retrieved data complies with the CakePHP data structure. Release 2. 'alias' => 'Channel'. you could add conditions based on Related model fields: $options['joins'] = array( array('table' => 'channels'.id = Item.id = Item.channel_id'. 'conditions' => array( 'Channel. The name of the model associated with the table is the best bet. 'type' => 'LEFT'. The keys that define the join are the following: • table: The table for the join. In the above example.private' => 1 ). adding a ‘joins’ key to the $options array. Here is where forcing joins comes to the rescue. Note: Remember that you need to set the recursion to -1 for this to work: $this->Channel->recursive = -1. But this is not the case with hasMany and hasAndBelongsToMany associations.channel_id'. • type: The type of join: inner. ) ) ).x In CakePHP. left or right. • alias: An alias to the table. For example: $options['joins'] = array( array('table' => 'channels'. • conditions: The conditions to perform the join. 'alias' => 'Channel'.CakePHP Cookbook Documentation. $options['conditions'] = array( 'Channel. Models . some associations (belongsTo and hasOne) perform automatic joins to retrieve data. so you can issue queries to retrieve models based on data in the related one. To force a join between tables. 226 Chapter 6. ) ) ). 'type' => 'LEFT'. $options). You only have to define the necessary joins to combine tables and get the desired results for your query. 'conditions' => array( 'Channel. Note: Note that the ‘joins’ arrays are not keyed.

’first’. You could perform several joins as needed in hasAndBelongsToMany: Suppose there is a Book hasAndBelongsToMany Tag association. sort it. 'alias' => 'BooksTag'. Keep in mind that $type is case-sensitive. Retrieving Your Data As stated before. $type can be ’all’. 'conditions' => array( 'Book.id' ) ) ). ’neighbors’ or ’threaded’. paginate it. 'conditions' => array( 'BooksTag. ’count’. This relation uses a books_tags table as a join table. into ill-formed SQL queries if combined with any of the former techniques described for associating models. Using an upper case character (for example. array('table' => 'tags'. or any custom finder you can define. ’list’.CakePHP Cookbook Documentation. $books = $Book->find('all'. Release 2. The CakePHP Model class comes with some functions that will help you search for this data. The most common function you will use in models is Model::find() find find(string $type = ’first’.x $privateItems = $Item->find('all'. $options['conditions'] = array( 'Tag. All) will not produce the expected results. 'type' => 'inner'. $options). one of the roles of the Model layer is to get data from multiple types of storage.id = BooksTag. array $params = array()) Find is the multifunctional workhorse of all model data-retrieval functions. 'alias' => 'Tag'. binding models on the fly and using the Containable behavior.book_id' ) ). you can use other tools to achieve the same results such as correctly defining associations. so you need to join the books table to the books_tags table. and this with the tags table: $options['joins'] = array( array('table' => 'books_tags'. However.tag' => 'Novel' ). $options). 'type' => 'inner'.tag_id = Tag. Using joins allows you to have maximum flexibility in how CakePHP handles associations and fetches the data. More on models 227 . This feature should be used with care because it could lead. in a few cases. in most cases. and filter it.

and your own model methods can.field' => $thisValue).CakePHP Cookbook Documentation. 'Model.field3 DESC'). Release 2. //int //array of field names 'fields' => array('Model.created' => 'desc') )). find(‘first’) find(’first’. //int 'offset' => n. The format returned from find(’first’) call is of the form: Array ( [ModelName] => Array ( [id] => 83 [field1] => value1 [field2] => value2 [field3] => value3 ) [AssociatedModelName] => Array 228 Chapter 6.field').. array( 'conditions' => array('Article. // . array( 'order' => array('Article. //int 'page' => n. Below are a couple of simple (controller code) examples: public function some_function() { // . $semiRandomArticle = $this->Article->find('first').field2'). all of which are optional: array( 'conditions' => array('Model. If your find() operation fails to match any records. and has the following possible keys by default. $params) will return one result.x $params is used to pass all parameters to the various types of find(). //int 'callbacks' => true //other possible values are false. so no conditions or sort order will be used. } In the first example. //string or array defining order 'order' => array('Model.created'.field1'. 'before'.. 'group' => array('Model. //fields to GROUP BY 'limit' => n. Models .. 'DISTINCT Model. 'after' ) It’s also possible to add and use other parameters. //array of conditions 'recursive' => 1. you will get an empty array. You’d use this for any case where you expect only one result. $specificallyThisOne = $this->Article->find('first'. too. no parameters at all are passed to find.id' => 1) )).. Some types of find() and behaviors make use of this ability. $lastCreated = $this->Article->find('first'.

$publishedAuthors = $this->Article->find('count'... array( 'conditions' => array('Article. the count is always the same. $total = $this->Article->find('count'). Below are a couple of simple (controller code) examples: public function some_function() { // . find(‘all’) find(’all’. // .. $allAuthors = $this->Article->User->find('all'). the mechanism used by all find() variants. $pending = $this->Article->find('count'. } Note: Don’t pass fields as an array to find(’count’). array( 'fields' => 'DISTINCT Article.. dictated by the conditions).status !=' => 'pending') )). $params) returns an integer value. array( 'conditions' => array('Article.. } More on models 229 . $allArticles = $this->Article->find('all'). 'conditions' => array('Article.x ( [id] => 1 [field1] => value1 [field2] => value2 [field3] => value3 ) ) find(‘count’) find(’count’.status !=' => 'pending') )). Release 2. It is... // .status' => 'pending') )).CakePHP Cookbook Documentation. Below are a couple of simple (controller code) examples: public function some_function() { // .user_id'. array( 'conditions' => array('Article. in fact. $allPublishedAuthors = $this->Article->User->find('all'. $authors = $this->Article->User->find('count').status' => 'pending') )). You would only need to specify fields for a DISTINCT count (since otherwise. $pending = $this->Article->find('all'. $params) returns an array of potentially multiple results.. as well as paginate.

since none were passed. $allArticles = $this->Article->find('list').x Note: In the above example. such as for populating input select boxes. $pending = $this->Article->find('list'.CakePHP Cookbook Documentation. $allAuthors will contain every user in the users table. array( 'conditions' => array('Article. array( 'fields' => array('User. Below are a couple of simple (controller code) examples: public function some_function() { // . 230 Chapter 6.. $params) returns an indexed array. 'conditions' => array('Article. The results of a call to find(’all’) will be of the following form: Array ( [0] => Array ( [ModelName] => Array ( [id] => 83 [field1] => value1 [field2] => value2 [field3] => value3 ) [AssociatedModelName] => Array ( [id] => 1 [field1] => value1 [field2] => value2 [field3] => value3 ) ) ) find(‘list’) find(’list’. $allPublishedAuthors = $this->Article->find('list'. Release 2.. There will be no condition applied to the find.id'. // . $allAuthors will contain every user in the users table. $allAuthors = $this->Article->User->find('list').status !=' => 'pending'). useful for any place where you would want a list. 'User. } Note: In the above example. There will be no condition applied to the find.name'). since none were passed.. Models ..status' => 'pending') )). 'recursive' => 0 )).

[213] => 'AD7six'. the primary key for the model is used for the key. When calling find(’list’). array( 'fields' => array('User. 'User. ['gwoo'] => 'Gwoo'.first_name') )). 'displayValue6'. [1] => 'PHPNut'. 'displayValue3'. array( 'fields' => array('User. 'displayValue2'. // . By default.. 'displayValue1'. 'User. [2] => 'gwoo'. the fields passed are used to determine what should be used as the array key and value.CakePHP Cookbook Documentation. [400] => 'jperras'. 'User.username') )).. the resultant vars would look something like this: $justusernames = Array ( //[id] => 'username'. ) $usernameMap = Array ( //[username] => 'firstname'.username'.group') )). [25] => '_psychic_'. array( 'fields' => array('User. $usernameMap = $this->Article->User->find('list'. } With the above code example. ['_psychic_'] => 'John'. $usernameGroups = $this->Article->User->find('list'.x The results of a call to find(’list’) will be in the following form: Array ( //[id] [1] => [2] => [4] => [5] => [6] => [3] => ) => 'displayValue'. ['jperras'] => 'Joël'.username'. Some further examples to clarify: public function some_function() { // .first_name'. Release 2. 'displayValue5'. and the display field (which can be configured using the model attribute displayField) is used for the value. ['PHPNut'] => 'Larry'. and optionally what to group the results by. $justusernames = $this->Article->User->find('list'. ['AD7six'] => 'Andy'. ) More on models 231 ... 'displayValue4'.

. $allCategories = $this->Category->find('threaded'). ['jperras'] => 'Joël'..x $usernameGroups = Array ( ['User'] => Array ( ['PHPNut'] => 'Larry'. } Tip: A better way to deal with nested data is using the Tree behavior In the above code example. Release 2. $allCategories will contain a nested array representing the whole category structure. Models . The results of a call to find(’threaded’) will be of the following form: Array ( [0] => Array ( [ModelName] => Array ( [id] => 83 [parent_id] => null [field1] => value1 [field2] => value2 [field3] => value3 ) 232 Chapter 6. ) ) find(‘threaded’) find(’threaded’. // .. array( 'conditions' => array('article_id' => 50) )). $comments = $this->Comment->find('threaded'.CakePHP Cookbook Documentation. ['AD7six'] => 'Andy'. $params) returns a nested array. and is appropriate if you want to use the parent_id field of your model data to build nested results.. ['gwoo'] => 'Gwoo'. ) ['Admin'] => Array ( ['_psychic_'] => 'John'. Below are a couple of simple (controller code) examples: public function some_function() { // .

. the results will appear in name order.CakePHP Cookbook Documentation. Warning: If you specify fields. For example. } Otherwise. as it is influenced by the order of processing. you need to always include the id and parent_id (or their current aliases): public function some_function() { $categories = $this->Category->find('threaded'. More on models 233 . Any order can be used. 'parent_id') )). array( 'fields' => array('id'.x [AssociatedModelName] => Array ( [id] => 1 [field1] => value1 [field2] => value2 [field3] => value3 ) [children] => Array ( [0] => Array ( [ModelName] => Array ( [id] => 42 [parent_id] => 83 [field1] => value1 [field2] => value2 [field3] => value3 ) [AssociatedModelName] => Array ( [id] => 2 [field1] => value1 [field2] => value2 [field3] => value3 ) [children] => Array ( ) ) . 'name'. Release 2. if ’order’ => ’name ASC’ is passed in the params to find(’threaded’).. the returned array will not be of the expected nested structure from above. there is no built-in requirement of this method for the top result to be returned first. ) ) ) The order in which results appear can be changed.

) The result returned from a find(’neighbors’) call is in the form: Array ( [prev] => Array ( [ModelName] => Array ( [id] => 2 [field1] => value1 [field2] => value2 .... Release 2. ) ) [next] => Array ( [ModelName] => Array ( [id] => 4 [field1] => value1 [field2] => value2 .. ) [AssociatedModelName] => Array ( [id] => 151 [field1] => value1 [field2] => value2 . array('field' => 'id'. $params) will perform a find similar to ‘first’.. (For example: If your model acts as containable..x find(‘neighbors’) find(’neighbors’. Models . ) 234 Chapter 6. but will return the row before and after the one you request.CakePHP Cookbook Documentation.. ) [AssociatedModelName] => Array ( [id] => 122 [field1] => value1 [field2] => value2 . Other elements are still allowed as with any other find. then you can specify ‘contain’ in $params. Below is a simple (controller code) example: public function some_function() { $neighbors = $this->Article->find( 'neighbors'.. } You can see in this example the two required elements of the $params array: field and value. 'value' => 3) ).

return $query. The recursive setting must be passed in the parameters on each call. This is done by convention. This function does not honor a model’s default recursive var. $this->User->find('all'. Release 2. If you wanted to implement a finder called myFancySearch. For example. } } More on models 235 . Basically this is just telling CakePHP to accept the value available as the first argument of the find function. A Model Find Type is a shortcut to find() options. then the method to implement would be named _findMyFancySearch.published'] = true. class Article extends AppModel { public $findMethods = array('available' => true). Creating custom find types The find method is flexible enough to accept your custom finders.x ) ) Note: Note how the result always contains only two root elements: prev and next. The next step is to implement the function _findAvailable. This is done by declaring your own types in a model variable and by implementing a special function in your model class. array('limit' => 1)). The following are core find types: • first • all • count • list • threaded • neighbors But what about other types? Let’s say you want a finder for all published articles in your database. } return $results. protected function _findAvailable($state. The first change you need to do is add your type to the Model::$findMethods variable in the model class Article extends AppModel { public $findMethods = array('available' => } true). $results = array()) { if ($state === 'before') { $query['conditions']['Article.CakePHP Cookbook Documentation. $query. the following two finds are equivalent $this->User->find('first').

To simply return the count of a custom find type. and interpret any special key that is passed in the second argument of find. and they are a great way of reusing code in your application across models. Typically the first thing to check in our custom find function is the state of the query. $this->set(compact('articles')). or do whatever you like to the recently fetched data. call count like you normally would. but pass in the find type in an array for the second argument. and will also allow you to continue to modify the find results. } } The special _find[Type] methods receive three arguments as shown above. It is done this way because this function is just a sort of callback function that has the ability to modify the query before it is done. class ArticlesController extends AppController { // Will find the count of all published articles (using the available find defined abov public function index() { $count = $this->Article->find('count'. The before state is the moment to modify the query. Release 2. The after state is the perfect place to inspect the results. array( 236 Chapter 6. inject new data. This state requires you to return the $results array (modified or not).x This all comes together in the following example (controller code): class ArticlesController extends AppController { // Will find all published articles and order them by the created column public function index() { $articles = $this->Article->find('available'. The first one means the state of the query execution. or to modify the results after they are fetched. It is also possible to paginate via a custom find type using the ‘findType’ option as follows: class ArticlesController extends AppController { // Will paginate all published articles public function index() { $this->paginate = array('findType' => 'available'). which could be either before or after. bind new associations. $articles = $this->paginate(). process it in order to return it in another format. array( 'order' => array('created' => 'desc') )). apply more behaviors. This state requires you to return the $query argument (modified or not). Models . } } Setting the $this->paginate property as above on the controller will result in the type of the find becoming available. You can create as many custom finders as you like.CakePHP Cookbook Documentation.

it may be necessary to add the following code to your AppModel. You no longer need to override _findCount for fixing incorrect count results. which should fix the pagination count: class AppModel extends Model { /** * Removes 'fields' key from count query on custom finds when it is an array. $results = array()) { if ($state === 'before') { $query['conditions']['Article. $query. $query).CakePHP Cookbook Documentation. $query. ucfirst($query['type']) }('before'. } } If your pagination page count is becoming corrupt. or false * @access protected * @see Model::find() */ protected function _findCount($state. Release 2. } More on models 237 . $query. } } ?> Changed in version 2. if (!empty($query['fields']) && is_array($query['fields'])) { if (!preg_match('/^count/i'.published'] = true. The ’before’ state of your custom finder will now be called again with $query[’operation’] = ‘count’. you can distinguish by checking the ’operation’ key and return a different $query: protected function _findAvailable($state. } } } } return parent::_findCount($state. The returned $query will be used in _findCount() If necessary. if (!empty($query['operation']) && $query['operation'] === 'count') { return $query. * as it will completely break the Model::_findCount() call * * @param string $state Either "before" or "after" * @param array $query * @param array $results * @return int The number of records found. $results).2. current($query['fields']))) { unset($query['fields']). $results = array()) { if ($state === 'before') { if (isset($query['type']) && isset($this->findMethods[$query['type']])) { $query = $this->{ '_find' .x 'type' => 'available' )).

order_status = 3 $this->Recipe->findAllByType(’Cookie’). // Is equivalent to $this->Article->find('published'. } return $results. you can use those finders with the magic findBy method: $results = $this->Article->findPublishedByAuthorId(5). Just add the name of the field (in CamelCase format) to the end of these functions.email = ’jhon’ OR ’jhon’). if your model implements a published finder. array(’User. User. int $limit.user_name => ORDER BY User. int $recursive) findAllBy<x> Example Corresponding SQL Fragment $this->Product->findAllByOrderStatus(’3’). Models .last_name = ’psychic’ array().last_name = ’Anderson’ $this->Cake->findAllById(7).CakePHP Cookbook Documentation. ASC The returned result is an array formatted just as it would be from find(’all’). findAllBy() functions will return results in a format like find(’all’). User. User. you can use any custom finder method with the magic method interface. array $order.8.password = ’123’. int $page. and supply the criteria for that field as the first parameter. Recipe.x $query['joins'] = array( //array of required joins ). $this->User->findAllByUsernameAndPassword(’jhon’. } Magic Find Types These magic functions can be used as a shortcut to search your tables by a certain field. Custom Magic Finders As of 2. array( 238 Chapter 6.type = ’Cookie’ $this->User->findAllByLastName(’Anderson’).id = 7 $this->User->findAllByEmailOrUsername(’jhon’.User. while findBy() return in the same format as find(’first’) findAllBy findAllBy<fieldName>(string $value. Product. $this->User->findAllByLastName(’psychic’. array $fields. return $query. Release 2.user_name ’asc’)). For example. User. Cake.username = ’jhon’ AND ’123’). User.username = ’jhon’.

Recipe.email = ’jhon’ OR ’jhon’). mixed $fields[."). might return: Array ( [0] => Array ( More on models 239 . New in version 2. Note: query() does not honor $Model->cacheQueries as its functionality is inherently disjoint from that of the calling model. The findBy magic functions also accept some optional parameters: findBy<fieldName>(string $value[. ie: query($query.username = ’jhon’ AND ’123’).type = ’Cookie’ $this->User->findByLastName(’Anderson’). findBy<x> Example Corresponding SQL Fragment $this->Product->findByOrderStatus(’3’).8. User. $this->User->findByUsernameAndPassword(’jhon’. Cake. To avoid caching calls to query. For example: $this->Picture->query("SELECT * FROM pictures LIMIT 2.id = 7 findBy() functions return results like find(’first’) Model::query() query(string $query) SQL calls that you can’t or don’t want to make via other model methods can be made using the model’s query() method (though this should only rarely be necessary). supply a second argument of false. $cachequeries = false) query() uses the table name in the query as the array key for the returned data. Failing to escape parameters will create SQL injection vulnerabilities.author_id' => 5) )). $this->Cake->findById(7). Product.0: Custom magic finders were added in 2.0. be sure to properly escape all parameters using the value() method on the database driver.username = ’jhon’.CakePHP Cookbook Documentation. User.password = ’123’. rather than the model name. User. findBy findBy<fieldName>(string $value).x 'conditions' => array('Article. If you use this method.order_status = 3 $this->Recipe->findByType(’Cookie’). User. User. Release 2.last_name = ’Anderson’. mixed $order]]). $this->User->findByEmailOrUsername(’jhon’.8.

CakePHP does not provide any data abstraction when running queries manually. Model::field() field(string $name.CakePHP Cookbook Documentation. the query can be rewritten: $this->Picture->query("SELECT * FROM pictures AS Picture LIMIT 2. Models . and get a result consistent with that returned by the Find methods. which returns: Array ( [0] => Array ( [Picture] => Array ( [id] => 1304 [user_id] => 759 ) ) [1] => Array ( [Picture] => Array ( [id] => 1305 [user_id] => 759 ) ) ) Note: This syntax and the corresponding array structure is valid for MySQL only. string $order = null) 240 Chapter 6.x [pictures] => Array ( [id] => 1304 [user_id] => 759 ) ) [1] => Array ( [pictures] => Array ( [id] => 1305 [user_id] => 759 ) ) ) To use the model name as the array key. so exact results will vary between databases. array $conditions = null. Release 2.").

CakePHP prefers using arrays for expressing any conditions that need to be put after the WHERE clause in any SQL query. ensure proper SQL syntax. Doing so will make you vulnerable to SQL injections. Use field to retrieve the value of a single field. is used. especially using it in the model callback functions such as beforeValidate and beforeSave. Warning: As the read method overwrites any information stored in the data and id property of the model.x Returns the value of a single field. 'created DESC' ). from the first record matched by $conditions as ordered by $order. This syntax also breaks out the elements of your query (fields. operators. all fields will be fetched. as specified by Model::$id. read() always returns an array (even if only a single field name is requested). $fields is used to pass a single field name. // echo the name for row id 22 // echo the name of the last created instance echo $this->Post->field( 'name'. If no matching record is found. you should be very careful when using this function in general. as a string. $this->Post->id = 22. Model::read() read($fields. the currently selected record. Warning: CakePHP only escapes the array values. Generally the find function provides a more robust and easy to work with API than the read method. values. By default. manipulatable parts. Using the array syntax also enables CakePHP to secure your queries against any SQL injection attack. $id specifies the ID of the record to be read. You should never put user data into the keys. it returns false.) into discrete. If no conditions are passed and the model id is set. Passing a different value to $id will cause that record to be selected. echo $this->Post->field('name'). and also makes it very easy to build queries. Complex Find Conditions Most of the model’s find calls involve passing sets of conditions in one way or another. array('created <' => date('Y-m-d H:i:s')). In general. More on models 241 . or an array of field names. and properly escape each individual part of the query.CakePHP Cookbook Documentation. $id) read() is a method used to set the current model data (Model::$data)–such as during edits–but it can also be used in other circumstances to retrieve a single record from the database. Release 2. if left empty. Using arrays is clearer and easier to read. specified as $name. This allows CakePHP to generate the most efficient query possible. it will return the field value for the current model result. etc.

. Release 2. What about other types of matches? These are equally simple. it will return posts that have never been modified). should you choose to change your schema..title" => "This is a post". "Second post". // other conditions as usual ) 242 Chapter 6.created = Post. The one exception here is IN (. "Second post".created >" => date('Y-m-d'.)-style matches.field & 8 = 1'.author_id" => 1).modified") The above example will return posts where the created date is equal to the modified date (that is. Note that we could have used just “title” as the field name. "Third post") ) To do a NOT IN(. BETWEEN. boolean operations). but when building queries. Let’s say you wanted to find posts where the title was in a given set of values: array( "Post.CakePHP Cookbook Documentation. as it improves the clarity of the code.title" => array("First post". it is good practice to always specify the model name.title" => array("First post". // Example usage with a model: $this->Post->find('first'. Remember that if you find yourself unable to form a WHERE clause in this method (for example. including match expressions using LIKE. an array-based query looks like this: $conditions = array("Post. "Post.title" => array("First post".. Let’s say we wanted to find all the posts where the title is not “This is a post”: array("Post. "Third post"). The structure here is fairly self-explanatory: it will find any post where the title equals “This is a post” and the author id is equal to 1. you can always specify it as a string like: array( 'Model. "Third post") ) ) Adding additional filters to the conditions is as simple as adding additional key/value pairs to the array: array ( "Post.) match to find posts where the title is not in the given set of values. strtotime("-2 weeks")) ) You can also create finds that compare two fields in the database: array("Post. CakePHP can parse out any valid SQL comparison operator.. do the following: array( "NOT" => array( "Post. as long as you leave a space between field name and the operator. Models .x At its most basic. and helps prevent collisions in the future. "Second post".title !=" => "This is a post") Notice the ‘!=’ that follows the field name. or REGEX. array('conditions' => $conditions)). "Post.

created >" => date('Y-m-d'. including AND. strtotime("-2 weeks")) ) ) If you need to set multiple conditions on the same field. the query will return records where the post title is not null: array("NOT" => array( "Post.title LIKE' => '%two%') )) The wildcard operators ILIKE and RLIKE (RLIKE since version 2. whichever you prefer.title LIKE' => '%one%').. like when you want to do a LIKE search with multiple terms.name" => "Bob".10)) Note: CakePHP will quote the numeric values depending on the field type in your DB. However.type'.read_count BETWEEN ? AND ?' => array(1.price) as price' More on models 243 . strtotime("-2 weeks")) )) CakePHP accepts all valid SQL boolean operations. "Post. NOT.title LIKE" => "%magic%". array('Post. 'MIN(Product. you can use the following: array('Post.title" => array("First post". In this example. This means the snippet below would only match posts that have been created in the past two weeks.6) are also available. "Post. we could just as easily find posts that match either condition: array("OR" => array( "Post. and have a title that matches one in the given set. but you wanted to restrict your search to posts written by Bob: array( "Author.title" => null ) ) To handle BETWEEN queries. you can do so by using conditions similar to: array('OR' => array( array('Post. "OR" => array( "Post. "Third post"). Let’s say you had a belongsTo relationship between Posts and Authors. XOR.x By default. CakePHP joins multiple conditions with boolean AND.CakePHP Cookbook Documentation. CakePHP can also check for null fields. etc. OR. "Second post".created >" => date('Y-m-d'. These conditions are also infinitely nestable. and they can be upper or lower case. How about GROUP BY?: array( 'fields' => array( 'Product. Let’s say you wanted to find all the posts that contained a certain keyword (“magic”) or were created in the past two weeks. Release 2.

CakePHP Cookbook Documentation.`description`. `Company`.. `Company`. Models .. etc. in a similar fashion: array( 'fields' => array('DISTINCT (User.`name`..name' => 'Future Holdings'). 'group' => 'Product.type' ) The data returned for this would be in the following format: Array ( [0] => Array ( [Product] => Array ( [type] => Clothing ) [0] => Array ( [price] => 32 ) ) [1] => Array . 'order' =>array('User. 'NOT' => array( array('Company.`status`. `Company`.status' => array('inactive'. MAX(). `Company`. such as MIN(). You can use other operators. `Company`.`size` 244 Chapter 6.`created`. A quick example of doing a DISTINCT query.city' => 'CA') ). 'AND' => array( array( 'OR' => array( array('Company.`location`. 'suspended')) ) ) ) ) ) which produces the following SQL: SELECT `Company`. Release 2. array('Company.id DESC') ) You can create very complex conditions by nesting multiple condition arrays: array( 'OR' => array( array('Company. `Company`.name) AS my_column_name').x ).status' => 'active').`id`.

$subQueryExpression = $db->expression($subQuery). $conditions[] = $subQueryExpression.`name` = 'Future Holdings') OR (`Company`. 'conditions' => $conditionsSubQuery."status" AS "User__status" FROM "users" AS "User" More on models 245 ."name" AS "User__name". “name” and “status”. "User". $this->User->find('all'. “B” or “C”. We want to retrieve all the users that have status other than “B” using a sub-query.`city` = 'CA')) AND ((`Company`. but it will just return the SQL statement.`status` = 'active') OR (NOT (`Company`."id" NOT IN (' . 'order' => null. compact('conditions')). 'alias' => 'User2'."id" AS "User__id". 'suspended')))) Sub-queries For this example. imagine that we have a “users” table with “id”."status"'] = 'B'. $db = $this->User->getDataSource(). ') '. 'group' => null ). $subQuery .x FROM `companies` AS `Company` WHERE ((`Company`. we are going to get the model data source and ask it to build the query as if we were calling a find() method. 'limit' => null.`status` IN ('inactive'. $subQuery = ' "User". After that we make an expression and add it to the conditions array: $conditionsSubQuery['"User2". The status can be “A”."id"'). This should generate the following SQL: SELECT "User". $this->User ). $subQuery = $db->buildStatement( array( 'fields' => array('"User2". 'table' => $db->fullTableName($this->User). "User". Release 2. 'joins' => array(). 'offset' => null. In order to achieve that.CakePHP Cookbook Documentation.

'12345') ). Data ready to be saved should be passed to the model’s save() method using the following basic format: Array ( [ModelName] => Array ( [fieldname1] => 'value' [fieldname2] => 'value' ) ) Most of the time you won’t even need to worry about this format: CakePHP’s FormHelper. datasource expressions with raw SQL work for any part of the find query.x WHERE "User". $db->fetchAll( 'SELECT * from users where username = :username AND password = :password'. array('username' => 'jhon'."id" NOT IN ( SELECT "User2". Release 2.'password' => '12345') ). Saving Your Data CakePHP makes saving model data a snap. Models . $db->fetchAll( 'SELECT * from users where username = ? AND password = ?'. If you’re using FormHelper. the data is also conveniently available in $this->request->data for quick usage. array('jhon'."id" FROM "users" AS "User2" WHERE "User2". if you need to pass just part of your query as raw SQL as above. Prepared Statements Should you need even more control over your queries. and model find methods all package data in this format. Here’s a quick example of a controller action that uses a CakePHP model to save data to a database table: public function edit($id) { // Has any form data been POSTed? if ($this->request->is('post')) { 246 Chapter 6."status" = 'B' ) Also. you can make use of prepared statements.CakePHP Cookbook Documentation. This allows you to talk directly to the database driver and send any custom query you like: $db = $this->getDataSource().

} When save is called. Is an example of how you can use set() to update single fields.. $this->Post->set(array( 'title' => 'New title'. $this->Post->save().x // If the form data can be validated and saved. More on models 247 . } } // If no form data. There are a few other save-related methods in the model that you’ll find useful: Model::set($one. You can also use set() to assign new values to multiple fields: $this->Post->read(null. $this->Recipe->findById($id)). the data passed to it in the first parameter is validated using CakePHP’s validation mechanism (see Data Validation chapter for more information). 'New title for the article').. be sure to check to see if some validation rules are being broken. if ($this->Recipe->save($this->request->data)) { // Set a session flash message and redirect.CakePHP Cookbook Documentation. find the recipe to be edited // and hand it to the view. You can debug this situation by outputting Model::$validationErrors: if ($this->Recipe->save($this->request->data)) { // handle the success. return $this->redirect('/recipes').4. Release 2. 'published' => false )). If for some reason your data isn’t saving. 1). New in version 2. 1). $this->Session->setFlash('Recipe Saved!'). This is useful when using models with the ActiveRecord features offered by Model: $this->Post->read(null. $this->Post->set('title'. $this->set('recipe'. Model::clear() This method can be used to reset model state and clear out any unsaved data and validation errors. $two = null) Model::set() can be used to set one or many fields of data to the data array inside a model. $this->Post->save(). The above would update the title and published fields and save the record to the database. in an ActiveRecord approach. } debug($this->Recipe->validationErrors).

4) Boolean to control updating of counter caches (if any) • atomic (since 2. 248 Chapter 6.6) Boolean to indicate you want records saved in a transaction.CakePHP Cookbook Documentation. If $Model->id is set. $this->Recipe->save($this->request->data).x Model::save(array $data = null. • callbacks Set to false to disable callbacks. array $params = array()) $params array can have any of the following available options as keys: • validate Set to true/false to enable/disable validation. Creating or updating is controlled by the model’s id field. The save method also has an alternate syntax: save(array $data = null. Otherwise a new record is created: // Create: id isn't set or is null $this->Recipe->create(). For added security. • counterCache (since 2. this method saves array-formatted data. Models . Using ‘before’ or ‘after’ will enable only those callbacks. and by this change fields that were not originally intended to be changed. More information about model callbacks is available here Tip: If you don’t want the modified field to be automatically updated when saving some data add ’modified’ => false to your $data array Once a save has been completed. the ID for the object can be found in the $id attribute of the model object . the record with this primary key is updated. $this->Recipe->save($this->request->data). array $fieldList = array()) Featured above. you can limit the saved fields to those listed in $fieldList. // Update: id is set to a numerical value $this->Recipe->id = 2. $this->Ingredient->save($newData). boolean $validate = true. $newIngredientId = $this->Ingredient->id. The second parameter allows you to sidestep validation. Note: If $fieldList is not supplied. Tip: When calling save in a loop. Release 2.something especially handy when creating new objects. a malicious user can add additional fields to the form data (if you are not using SecurityComponent). don’t forget to call clear(). • fieldList An array of fields you want to allow for saving. and the third allows you to supply a list of model fields to be saved.

CakePHP Cookbook Documentation.x If you want to update a value. $fieldName should only contain the name of the field. to update the title of a blog post. it will be merged with the database field defaults and the model instance will be ready to save with that data (accessible at $this->data). array $params = array()) $params array can have any of the following available options as keys: • validate Set to true/false to enable/disable validation. Model::create(array $data = array()) This method resets the model state for saving new information. Release 2. $validate = false) Used to save a single field value. • counterCache (since 2. If you have not defined defaults for your database fields. This avoids conflicts with possible prior save calls in callbacks or other places. string $fieldValue. Warning: You can’t stop the modified field being updated with this method. When using this method. 'A New Title for a New Day'). // This will update Recipe with id 10 $this->Recipe->save($data). If the $data parameter (using the array format outlined above) is passed. Model::$data will be set to an empty array. make sure you are passing the primary key field into the data array: $data = array('id' => 10. Model::saveField(string $fieldName. For example. If false or null are passed for the $data parameter.4) Boolean to control updating of counter caches (if any) More on models 249 . It does not actually create a record in the database but clears Model::$id and sets Model::$data based on your database field defaults. The saveField method also has an alternate syntax: saveField(string $fieldName. string $fieldValue. 'title' => 'My new title'). Model::$data will be set to an empty array. not the name of the model and field. Using ‘before’ or ‘after’ will enable only those callbacks. you need to use the save() method. rather than create a new one. • callbacks Set to false to disable callbacks. Set the ID of the model ($this->ModelName->id = $id) just before calling saveField(). the call to saveField from a controller might look something like this: $this->Post->saveField('title'. Tip: If you want to insert a new row instead of updating an existing one you should always call create() first.

Model::saveMany(array $data = null. array('Baker. • fieldList: Equivalent to the $fieldList parameter in Model::save() 250 Chapter 6. The $fields array accepts SQL expressions. array $options = array()) Method used to save multiple rows of the same model at once. updateAll() will automatically join any belongsTo association for databases that support joins. Just add it manually to the array if you need it to be updated. ‘first’ to validate all records before any are saved (default). For example if one of your model methods was calling updateAll() you would do the following: $db = $this->getDataSource(). Note: Even if the modified field exists for the model being updated. Fields to be updated. the update call might look something like: $thisYear = date('Y-m-d H:i:s'. Release 2. By default.created <=' => $thisYear) ). If $conditions argument is not supplied or it is set to true. mixed $conditions) Updates one or more records in a single call. to close all tickets that belong to a certain customer: $this->Ticket->updateAll( array('Ticket. Models . temporarily unbind the associations. To prevent this. Should be set to false if database/table does not support transactions.approved' => true). For example. it is not going to be updated automatically by the ORM. The following options may be used: • validate: Set to false to disable validation.status' => "'closed'"). $value = $db->value($value. • atomic: If true (default). are identified by the $fields array. strtotime('-1 year')). along with their values. array('Baker.x Model::updateAll(array $fields. $this->updateAll( array('Baker. all records will be updated. Literal values should be quoted manually using DboSource::value(). Records to be updated are identified by the $conditions array.status' => $value). $this->Baker->updateAll( array('Baker. will attempt to save all records in a single transaction. array('Ticket. 'string'). to approve all bakers who have been members for over a year.status' => 'old') ). true to validate each record before saving.CakePHP Cookbook Documentation.customer_id' => 453) ). For example.

x • deep: (since 2. array('title' => 'title 2').4) Boolean to control updating of counter caches (if any) For saving multiple records of single model. 'Assoc' => array('field' => 'value') ). When saving multiple records of same model the records arrays should be just numerically indexed without the model key. 'Assoc' => array('field' => 'value')). $data needs to be a numerically indexed array of records like this: $data = array( array('title' => 'title 1'). Note: Note that we are passing numerical indexes instead of usual $data containing the Article key. array('deep' => true)). Using ‘before’ or ‘after’ will enable only those callbacks. array( // This updates an existing row 'Article' => array('id' => 2. see also saveAssociated() • callbacks Set to false to disable callbacks. $Model->saveMany($data. the two above examples would look like: $data = array( array('title' => 'title 1'. ). $data = array( array( 'Article' => array('title' => 'title 1'). array('title' => 'title 2'). array('Article' => array('title' => 'title 2')). Release 2. Keep in mind that if you want to update a record instead of creating a new one you just need to add the primary key index to the data row: $data = array( array( // This creates a new row 'Article' => array('title' => 'New article')). array('Article' => array('title' => 'title 2')).1). also associated data is saved. It is also acceptable to have the data in the following format: $data = array( array('Article' => array('title' => 'title 1')). ). ). ). • counterCache (since 2. ). 'title' => 'title 2')). More on models 251 .CakePHP Cookbook Documentation. To save also associated data with $options[’deep’] = true (since 2.1) If set to true.

the data array should be like this: $data = array( 'User' => array('username' => 'billy'). 'Cart' => array( array( 'payment_status_id' => 2. the data array should be as follow: $data = array( 'User' => array('email' => 'john-doe@cakephp. For saving a record along with its related records having hasMany association. • counterCache (since 2. • fieldList: Equivalent to the $fieldList parameter in Model::save() • deep: (since 2. array('body' => 'Comment 3'. not only directly associated data is saved. 252 Chapter 6. Defaults to false. the data array should be like this: $data = array( 'Article' => array('title' => 'My first article'). array('body' => 'Comment 2'. 'total_cost' => 250. true to validate each record before saving. array $options = array()) Method used to save multiple model associations at once. Models . will attempt to save all records in a single transaction. 'Comment' => array( array('body' => 'Comment 1'.x Model::saveAssociated(array $data = null. ). array( 'cart_product_id' => 5. 'quantity' => 1. 'user_id' => 1). 'quantity' => 1. 'occupation' => 'Programmer'). ).1) If set to true. And for saving a record along with its related records having hasMany with more than two levels deep associations.org'). ‘first’ to validate all records before any are saved (default). but deeper nested associated data as well. Release 2. 'user_id' => 40). ). • atomic: If true (default). The following options may be used: • validate: Set to false to disable validation. ).CakePHP Cookbook Documentation. 'user_id' => 12). Should be set to false if database/table does not support transactions. 'Profile' => array('sex' => 'Male'.4) Boolean to control updating of counter caches (if any) For saving a record along with its related record having a hasOne or belongsTo association. 'CartItem' => array( array( 'cart_product_id' => 3. 'cost' => 100.

array( 'fieldList' => array( 'SomeModel' => array('field_1').CakePHP Cookbook Documentation. The fieldList will be an array of model aliases as keys and arrays with fields as values. 'User' => array('first' => 'mad'. 'field_3') ) )). And save this data with: $Article->saveAssociated($data. the foreign key of the main model will be stored in the related models’ id field. The model names are not nested like in the data to be saved.1: Model::saveAll() and friends now support passing the fieldList for multiple models. ) ) ) ) ). Warning: Be careful when checking saveAssociated calls with atomic option set to false. Release 2.e. i. Example of using fieldList with multiple models: $this->SomeModel->saveAll($data.x 'cost' => 150. ). It returns an array instead of boolean. Changed in version 2. 'user_id' => 1). 'AssociatedModel' => array('field_2'. ). 'last' => 'coder') ). 'Comment' => array( array('body' => 'Comment 1'. array('deep' => true)). For saving a record along with its related records having hasMany association and deeper associated Comment belongsTo User data as well. More on models 253 . the data array should be like this: $data = array( 'Article' => array('title' => 'My first article'). Note: If successful. You can now save deeper associated data as well with setting $options[’deep’] = true. $this->RelatedModel->id. array( 'body' => 'Save a new user as well'.

if (!empty($user)) { // The ID of the newly created user has been set // as $this->User->id. hasMany. If you are saving a new Post and its associated Comments. array $options = array()) The saveAll function is just a wrapper around the saveMany and saveAssociated methods. saveMany will be called. otherwise saveAssociated is used.x Model::saveAll(array $data = null. } } } As a rule. 254 Chapter 6. and is generally a backwards compatible function. // If the user was saved. $this->request->data['Profile']['user_id'] = $this->User->id. Saving Related Model Data (hasOne. It is recommended using either saveMany or saveAssociated depending on the case. To get an idea of how this works. or parent model. CakePHP also offers a very handy method saveAssociated(). it is important to realize that saving model data should always be done by the corresponding CakePHP model. If neither of the associated model records exists in the system yet (for example. Now we add this information to the data // and save the Profile. you’ll need to first save the primary. To supplement the basic approach used above. hasMany. which allows you to validate and save multiple models in one shot. // Because our User hasOne Profile. belongsTo) When working with associated models. This function receives the same options as the former two. but other times it might just involve gathering the ID from a hidden input on a form that’s just been POSTed to a controller action. and belongsTo associations. Models . Release 2. you want to save a new User and their related Profile records at the same time). when working with hasOne. In addition. The example action shown below will assume that you’ve POSTed enough data (using the FormHelper) to create a single User and a single Profile: public function add() { if (!empty($this->request->data)) { // We can save the User data: // it should be in $this->request->data['User'] $user = $this->User->save($this->request->data). it’s all about keying. If data is formatted in a numerical indexed array. then you would use both Post and Comment models during the save operation.CakePHP Cookbook Documentation. it will inspect the data and determine what type of save it should perform. we can access // the Profile model through the User model: $this->User->Profile->save($this->request->data). The basic idea is to get the key from one model and place it in the foreign key field on the other. Sometimes this might involve using the $id attribute of the model class after a save(). let’s imagine that we have an action in our UsersController that handles the saving of a new User and a related Profile.

0. Our example involves the Head of Cake School asking us to write an application that allows him to log a student’s attendance on a course with days attended and grade. If the association between the models is hasOne. Now. $this->Form->input('Company. in our CompaniesController we can create an add() action: public function add() { if (!empty($this->request->data)) { // Use the following to avoid validation errors: unset($this->Company->Account->validate['company_id']).e. echo $this->Form->end('Add'). And having Account. Now our Company and Account models will be validated and saved all at the same time.fieldName notation for the associated model. the other models will not be saved either).location'). Note: The above field naming is required for a hasMany association. More on models 255 .0. the join table is associated to each model using a hasMany type of relationship. By default saveAssociated will validate all values passed and then try to perform a save for each. $this->Form->input('Company.0. First. If Company is our main model.name'.x saveAssociated() provides transactional support to ensure data integrity in your database (i. echo $this->Form->input('Account. you need to build your form for both Company and Account models (we’ll assume that Company hasMany Account): echo echo echo echo $this->Form->create('Company'. Let’s see how we can use saveAssociated() to save Company and Account models at the same time. Release 2.CakePHP Cookbook Documentation.0. array('label' => 'Account name')). array('action' => 'add')). Remember that MyISAM tables do not support transactions. Saving hasMany through data Let’s see how data stored in a join table for two models is saved. you have to use ModelName. if one model fails to save. Take a look at the way we named the form fields for the Account model.name'. echo $this->Form->input('Account. Take a look at the following code.fieldName is exactly what we need. } } That’s all there is to it.description').username'). saveAssociated() will expect the related model’s (Account) data to arrive in a specific format. Note: For transactions to work correctly in MySQL your tables must use InnoDB engine. echo $this->Form->input('Account. array('label' => 'Company name')).email'). As shown in the hasMany through (The Join Model) section. $this->Form->input('Company. $this->Company->saveAssociated($this->request->data).

?> <?php echo $this->Form->input('Student. ?> <?php echo $this->Form->input('CourseMembership. ?> <?php echo $this->Form->input('CourseMembership. } public function add() { if ($this->request->is('post')) { if ($this->CourseMembership->saveAssociated($this->request->data)) { return $this->redirect(array('action' => 'index')).last_name').x // Controller/CourseMembershipController.grade'). ?> <?php echo $this->Form->input('Student.ctp <?php echo $this->Form->create('CourseMembership'). public function index() { $this->set( 'courseMembershipsList'. Release 2.first_name'). ?> <?php echo $this->Form->input('Course.php class CourseMembershipsController extends AppController { public $uses = array('CourseMembership'). Array ( [Student] => Array ( [first_name] => Joe [last_name] => Bloggs ) [Course] => Array ( [name] => Cake ) [CourseMembership] => Array ( [days_attended] => 5 [grade] => A ) ) 256 Chapter 6. } } } } // View/CourseMemberships/add. $this->CourseMembership->find('all') ).CakePHP Cookbook Documentation. Models .days_attended'). ?> The data array will look like this when submitted.name'). ?> <button type="submit">Save</button> <?php echo $this->Form->end().

id'. There will be cases where you want to create the Student and Course independently and at a later point associate the two together with a CourseMembership. // View/CourseMemberships/add. If we run the index action of our CourseMembershipsController the data structure received now from a find(‘all’) is: Array ( [0] => Array ( [CourseMembership] => Array ( [id] => 1 [student_id] => 1 [course_id] => 1 [days_attended] => 5 [grade] => A ) [Student] => Array ( [id] => 1 [first_name] => Joe [last_name] => Bloggs ) [Course] => Array ( [id] => 1 [name] => Cake ) ) ) There are of course many ways to work with a join model. ?> <?php echo $this->Form->input( 'Student. e. 'label' => 'Student ID'.CakePHP Cookbook Documentation.x CakePHP will happily be able to save the lot together and assign the foreign keys of the Student and Course into CourseMembership with a saveAssociated call with this data structure. 'default' => 1 ) ).g.ctp <?php echo $this->Form->create('CourseMembership'). Release 2. ?> <?php echo $this->Form->input( More on models 257 . array( 'type' => 'text'. The version above assumes you want to save everything at-once. So you might have a form that allows selection of existing students and courses from pick lists or ID entry and then the two meta-fields for the CourseMembership.

belongsTo. ?> <?php echo $this->Form->input('CourseMembership.x 'Course.id'. Models .CakePHP Cookbook Documentation. and everything gets linked up correctly. ?> <button type="submit">Save</button> <?php echo $this->Form->end(). Saving Related Model Data (HABTM) Saving models that are associated by hasOne. array( 'type' => 'text'. 'default' => 1 ) ). 'label' => 'Course ID'. Once that’s done. Release 2. you just call the save() method on the model. and hasMany is pretty simple: you just populate the foreign key field with the ID of the associated model. ?> <?php echo $this->Form->input('CourseMembership. ?> And the resultant POST: Array ( [Student] => Array ( [id] => 1 ) [Course] => Array ( [id] => 1 ) [CourseMembership] => Array ( [days_attended] => 10 [grade] => 5 ) ) Again CakePHP is good to us and pulls the Student id and Course id into the CourseMembership with the saveAssociated.grade'). An example of the required format for the data array passed to save() for the Tag model is shown below: Array ( [Recipe] => Array ( [id] => 42 ) [Tag] => Array ( 258 Chapter 6.days_attended').

x [name] => Italian ) ) You can also use this format to save several records and their HABTM associations with saveAll().CakePHP Cookbook Documentation. Release 2. using an array like the following: Array ( [0] => Array ( [Recipe] => Array ( [id] => 42 ) [Tag] => Array ( [name] => Italian ) ) [1] => Array ( [Recipe] => Array ( [id] => 43 ) [Tag] => Array ( [name] => Pasta ) ) [2] => Array ( [Recipe] => Array ( [id] => 51 ) [Tag] => Array ( [name] => Mexican ) ) [3] => Array ( [Recipe] => Array ( [id] => 17 ) [Tag] => Array ( [name] => American (new) ) ) More on models 259 .

Another example that is helpful is when you need to save many Tags to a Post. 29) 260 Chapter 6.CakePHP Cookbook Documentation. 25. 12. Release 2. You need to pass the associated HABTM data in the following HABTM array format. 2. I Saw and I Conquered' ) [Tag] => Array ( [Tag] => Array(11. 9) ) ) [1] => Array ( [Post] => Array ( [title] => 'Dr Who\'s Name is Revealed' ) [Tag] => Array ( [Tag] => Array(7. 9. each associated with their respective recipes.x ) Passing the above array to saveAll() will create the contained tags. Models . Note you only need to pass in the id’s of the associated HABTM model however it needs to be nested again: Array ( [0] => Array ( [Post] => Array ( [title] => 'Saving HABTM arrays' ) [Tag] => Array ( [Tag] => Array(1. 15. 19) ) ) [2] => Array ( [Post] => Array ( [title] => 'I Came. 19) ) ) [3] => Array ( [Post] => Array ( [title] => 'Simplicity is the Ultimate Sophistication' ) [Tag] => Array ( [Tag] => Array(12. 22. 15. 5.

An input with the same name will automatically pull in this data into a <select>: // in the controller: $this->set('tags'. array(’deep’ => true)) will populate the posts_tags join table with the Tag to Post associations. a Recipe can have multiple Tags assigned to it. The simplest form might look something like this (we’ll assume that $recipe_id is already set to something): <?php echo $this->Form->create('Tag'). For example. ?> <?php echo $this->Form->end('Add Tag'). The tag name is defined using the ModelName convention: // in the controller: $this->set('tags'.x ) ) ) Passing the above array to saveAll($data. but the form input is declared slightly different. it’ll automatically save the HABTM data to the database: public function add() { // Save the association if ($this->Tag->save($this->request->data)) { // do something on success } } With the preceding code. When the save() method is invoked within the controller. In this case. ?> <?php echo $this->Form->input('Tag. you can see the Recipe. A more likely scenario with a HABTM relationship would include a <select> set to allow multiple selections.name'). ?> <?php echo $this->Form->input( 'Recipe. More on models 261 . As an example. Release 2. whose ID was set in $this->request->data[’Recipe’][’id’]. // in the view: $this->Form->input('tags'). $this->Recipe->Tag->find('list')).id'. we’ll build a form that creates a new tag and generates the proper data array to associate it on the fly with some recipe. $this->Recipe->Tag->find('list')). array('type' => 'hidden'.CakePHP Cookbook Documentation. Other ways we might want to present our associated data can include a select drop down list. ?> In this example. our new Tag is created and associated with a Recipe.id hidden field whose value is set to the ID of the recipe we want to link the tag to. the data is pulled out of the model the same way. The data can be pulled from the model using the find(’list’) method and assigned to a view variable of the model name. 'value' => $recipe_id) ).

allowing for multiple choices to automatically be saved to the existing Recipe being added or saved to the database. Consider this example: Child hasAndBelongsToMany Club Another way to look at this is adding a Membership model: 262 Chapter 6. but it is important to understand that you have an easy option. a multiple select drop down is created. Models . $this->Form->input('Project'). $this->Project->find('list')). By setting the className to the models name and use the alias as key we avoid those issues. class Project extends AppModel { public $hasAndBelongsToMany = array( 'RelatedProject' => array( 'className' => 'Project'. The key is in the model setup the className. $this->Form->input('RelatedProject'). } Creating form elements and saving the data works the same as before but you use the alias instead. though it requires some extra attention. Also note that if you want to add more fields to the join (when it was created or meta information) this is possible with HABTM join tables. ). HasAndBelongsToMany between two models is in reality shorthand for three models associated through both a hasMany and a belongsTo association.CakePHP Cookbook Documentation. You then update the Club with 2 children. The Club will only have 2 Children. Becomes this: $this->set('relatedProjects'. CakePHP will delete all rows on the join table before saving new ones. 'associationForeignKey' => 'projects_b_id'. This: $this->set('projects'. Release 2. Simply adding a Project HABTM Project relation causes issues saving data. For example if you have a Club that has 10 Children associated. $this->Project->find('list')). Using the preceding code. not 12. ). What to do when HABTM becomes complicated? By default when saving a HasAndBelongsToMany relationship. 'foreignKey' => 'projects_a_id'. Self HABTM Normally HABTM is used to bring 2 models together but it can also be used with only 1 model.x // in the view: $this->Form->input('Tag').

When you create your Model classes. etc. The important differences are that the “join” model is named differently and its behavior is more predictable. Additionally. Table names are by convention lowercase and pluralized with multi-word table names separated by underscores. Field names are by convention lowercase and separated by underscores.g. but without losing data from the extra fields during save operation. CakePHP will recognize those fields and populate them automatically whenever a record is created or saved to the database (unless the data being saved already contains a value for these fields). CakePHP will inspect your tables to determine the data type of each field and uses this information to automate various features such as outputting form fields in the view. You can create your database tables as you normally would. they’ll automatically map to the tables that you’ve created. most of the time. this is set automatically. CakePHP is designed to be agnostic and will work with MySQL. They use the same amount of named fields in the database and the same amount of models. The created and modified fields will be set to the current date and time when the record is initially added. More on models 263 . If you have created or modified data in your $this->data (e. if you used bake in order to create the models. a Model name of Ingredient expects the table name ingredients. The modified field will be updated with the current date and time whenever the existing record is saved. If you don’t want that you can use unset($this->data[’Model’][’modified’]). $validate = true. $fieldList = array()) { // Clear modified field value before each save $this->set($data). Tip: When your join table contains extra fields besides two foreign keys. Using created and modified By defining a created and/or modified field in your database table as datetime fields (default null). PostgreSQL and others. you can prevent losing the extra field values by setting ’unique’ array key to ’keepExisting’. A Model name of EventRegistration would expect a table name of event_registrations. You could think of this similar to ‘unique’ => true. Datatables While CakePHP can have datasources that aren’t database driven. Club Club hasMany Membership. belongsTo associations as shown in example above instead of using HABTM association. Release 2. from a Model::read or Model::set) before a Model::save() then the values will be taken from $this->data and not automagically updated. they are. These two examples are almost the exact same. However. See: HABTM association arrays.CakePHP Cookbook Documentation. in most cases it’s easier to make a model for the join table and setup hasMany. Microsoft SQL Server.x Child hasMany Membership Membership belongsTo Child. For example. Alternatively you can override the Model::save() to always do it for you: class AppModel extends Model { public function save($data = null.

the related Recipe records are also deleted if the model’s dependent-value is set to true. Release 2. If your database supports foreign keys and cascading deletes. e. • if $cascade is set to false. } return parent::save($this->data. the created and modified fields work like any other field. For example.g.CakePHP Cookbook Documentation. Deleting Data CakePHP’s Model class offers a few ways to delete records from your database. also deletes records dependent on the record specified to be deleted. When included in the fieldList. By default. boolean $cascade = true). deleteAll deleteAll(mixed $conditions. the fields will continue to have the values automatically assigned. See Callback Methods for more information.id')). delete delete(integer $id = null. } } If you are saving data with a fieldList and the created and modified fields are not present in the whitelist. The one benefit to using the cascade feature of Model::delete() is that it allows you to leverage behaviors and model callbacks: $this->Comment->delete($this->request->data('Comment. the Recipe records will remain after the User has been deleted.x if (isset($this->data[$this->alias]['modified'])) { unset($this->data[$this->alias]['modified']). $fieldList). $validate. $cascade = true. Deletes the record identified by $id. it’s often more efficient to rely on that feature than CakePHP’s cascading. Models . Note: If you delete a record with dependent records and one of their delete callbacks. $callbacks = false) 264 Chapter 6. beforeDelete returns false. You can hook custom logic into the delete process using the beforeDelete and afterDelete callbacks present in both Models and Behaviors. when deleting a User record that is tied to many Recipe records (User ‘hasMany’ or ‘hasAndBelongsToMany’ Recipes): • if $cascade is set to true. it will not stop the further event propagation nor does it change the return value of the initial delete.

} In the example above. as the conditions for the delete query were successful and no matching records remain. Run callbacks Return boolean True on success.spam' => true). Note: deleteAll() will return true even if no records are deleted. false). you might want to make sure that passwords are at least eight characters long. Associations will be reset before the matched records are deleted in deleteAll(). check out FormHelper. but the array contains no validation rules. This will often result in more queries being issued. Data Validation Data validation is an important part of any application. for example: To do that. Release 2.x deleteAll() is similar to delete(). The $conditions array should be supplied as a SQL fragment or array. you should set reset to false. The first step to data validation is creating the validation rules in the Model. There are many different aspects to the validation process. use the class User extends AppModel { public $validate = array(). Set to true to delete records that depend on this record • callbacks Boolean. Example: // Delete with array conditions similar to find() $this->Comment->deleteAll(array('Comment. except that deleteAll() will delete all records that match the supplied conditions. Defining validation rules makes form handling much. • conditions Conditions to match • cascade Boolean. Assuming that the users table has login. much easier. email and born fields. 'born' => 'date' ). If you delete with either callbacks and/or cascade. password. false on failure. the $validate array is added to the User Model. Model::validate array in the Model definition. or ensure that usernames are unique.CakePHP Cookbook Documentation. rows will be found and then deleted. Essentially: what happens when you call the save() method of your model. For example. If you use bindModel() or unbindModel() to change the associations. What we’ll cover in this section is the model side of things. 'email' => 'email'. the example below shows some simple validation rules that apply to those fields: class User extends AppModel { public $validate = array( 'login' => 'alphaNumeric'. } More on models 265 . as it helps to make sure that the data in a Model conforms to the business rules of the application. For more information about how to handle the displaying of validation errors.

let’s look at how these rules are defined in the model. Release 2. 'born' => array( 'rule' => 'date'. As the example above shows. The email should be a valid email address. and multiple rules per field. 266 Chapter 6. single rule per field. Models . notice how you can define specific error messages that CakePHP will use when these validation rules fail. and born should be a valid date. URLs.x This last example shows how validation rules can be added to model fields. Also. 'message' => 'Letters and numbers only' ). a single field can have multiple validation rules. Some of the built-in rules allow you to verify the formatting of emails. And if the built-in rules do not match your criteria. '8'). and credit card numbers – but we’ll cover these in detail later on. 5. only letters and numbers will be accepted. and its length should be between 5 and 15. Now that you’ve seen the big picture on how validation works. 'password' => array( 'rule' => array('minLength'. The password field should be a minimum of 8 characters long. CakePHP has many validation rules and using them can be quite easy. There are three different ways that you can define validation rules: simple arrays.CakePHP Cookbook Documentation. 'allowEmpty' => true ) ). 'required' => true. Defining validation rules enables CakePHP’s automagic showing of error messages in forms if the data submitted does not follow the defined rules. } Two validation rules are defined for login: it should contain letters and numbers only. and born should be a valid date. you can always add your own validation rules as required. For the login field. 15). 'email' => 'email'. 'between' => array( 'rule' => array('lengthBetween'. 'message' => 'Minimum 8 characters long' ). the email should be valid. 'message' => 'Between 5 to 15 characters' ) ). 'message' => 'Enter a valid date'. Here is a more complex validation example that takes advantage of some of these built-in validation rules: class User extends AppModel { public $validate = array( 'login' => array( 'alphaNumeric' => array( 'rule' => 'alphaNumeric'.

. ‘email’ or ‘isUnique’. ‘rule’ can be a single value e. If the rule does not require any parameters. 'allowEmpty' => false.x Simple Rules As the name suggests. Let’s have a closer look at these keys. This is because ‘required’ is not actually a rule. ‘fieldName’ is the name of the field the rule is defined for. the form validation will not function correctly. For more information on the rules available by default. or a regular expression. 'required' => true. One Rule Per Field This definition technique allows for better control of how the validation rules work. // or: 'update' 'on' => 'create'. ‘required’. public $validate = array( 'login' => array( 'rule' => 'alphaNumeric' ) ). Release 2. The specified ‘rule’ may be the name of a method in your model. If you only set ‘required’ => true.. For example. rule The ‘rule’ key defines the validation method and takes either a single value or an array. 'message' => 'Your Error Message' ) ). to ensure that the user is giving a well formatted email address.) 'rule' => 'ruleName'. As you can see here. More on models 267 . 'param1'. such as ‘alphaNumeric’. The ‘rule’ key is required. But before we discuss that. let’s see the general usage pattern adding a rule for a single field: public $validate = array( 'fieldName1' => array( // or: array('ruleName'. ‘on’ and ‘message’.g. 'param2' . ‘allowEmpty’.CakePHP Cookbook Documentation. Where. see Core Validation Rules. each field (only one field shown above) is associated with an array that contains five keys: ‘rule’. you could use this rule: public $validate = array('user_email' => 'email'). a method of the core Validation class. The general syntax for defining rules this way is: public $validate = array('fieldName' => 'ruleName'). and ‘ruleName’ is a pre-defined rule name. this is the simplest way to define a validation rule.

on The ‘on’ key can be set to either one of the following values: ‘update’ or ‘create’. For example. Therefore validation will fail if the field is not present in the dataset. While setting it to create or update will make the field required only for update or create operations. The numeric check is so that CakePHP does the right thing when $value is zero. The data sent to the model’s save() method must contain data for the login field. required => true does not mean the same as the validation rule notBlank(). Models . required => true indicates that the array key must be present . the ‘rule’ key is required for array-based rule definitions. or create or update.1: Support for create and update were added. ’allowEmpty’ => false makes sure that the current field value is nonempty. or during update of a record. if the validation rule has been defined as follows: public $validate = array( 'login' => array( 'rule' => 'alphaNumeric'. This provides a mechanism that allows a certain rule to be applied either during the creation of a new record.it does not mean it must have a value. where “nonempty” is defined as !empty($value) || is_numeric($value). the field value must be nonempty. Setting this key to true will make the field always required. whereas.x If the rule requires some parameters (like the max. min or range).CakePHP Cookbook Documentation. as described above. Release 2. but may (depending on the rule) succeed if the value submitted is empty (‘’). 268 Chapter 6. allowEmpty If set to false. required This key accepts either a boolean. the field must be present in the data array. ’required’ => true means that you cannot save the model without the key for this field being present in $this->data (the check is performed with isset). Changed in version 2. validation will fail. If ‘required’ is evaluated to true. ‘rule’ should be an array: public $validate = array( 'password' => array( 'rule' => array('minLength'. If it doesn’t. 'required' => true ) ). The difference between required and allowEmpty can be confusing. The default value for this key is boolean false. 8) ) ). Remember.

this is quite similar to what we did in the previous section. When ‘on’ is null. 8). The next technique we’ll outline allows us to assign multiple validation rules per model field. If you would like to assign multiple validation rules to a single field. Release 2. this is basically how it should look: public $validate = array( 'fieldName' => array( 'ruleName' => array( 'rule' => 'ruleName'. Note: Regardless of the rule. required.x If a rule has defined ‘on’ => ‘create’. Likewise..” Multiple Rules per Field The technique outlined above gives us much more flexibility than simple rules assignment. validation failure without a defined message defaults to “This field cannot be left blank. Each ‘ruleName’ contains a separate array of validation parameters.. go here. // extra keys like on. but there’s an extra step we can take in order to gain more fine-grained control of data validation. required. As you can see. the rule will only be enforced during the creation of a new record. the rule will be enforced during both creation and update. each ‘fieldName’ consists of an array of rule indexes. etc. // extra keys like on. etc.. for each field we had only one array of validation parameters. 'ruleName2' => array( 'rule' => 'ruleName2'. 'message' => 'Password must be at least 8 characters long' ) ). if it is defined as ‘on’ => ‘update’.CakePHP Cookbook Documentation. go here. message The message key allows you to define a custom validation error message for the rule: public $validate = array( 'password' => array( 'rule' => array('minLength'. ) ) ).. In this case. it will only be enforced during the updating of a record. The default value for ‘on’ is null. This is better explained with a practical example: public $validate = array( 'login' => array( 'loginRule-1' => array( More on models 269 . ). There.

270 Chapter 6. When specifying validation rules in this array form it’s possible to avoid providing the message key. ) ). If you want validation to continue in spite of a rule failing set key last to false for that rule. 8). When using multiple rules per field the ‘required’ and ‘allowEmpty’ keys need to be used only once in the first rule. Consider this example: public $validate = array( 'login' => array( 'Only alphabets and numbers allowed' => array( 'rule' => 'alphaNumeric'. Release 2. 'last' => false ). 'message' => 'Minimum length of 8 characters' ) ) ). 'message' => 'Minimum length of 8 characters' ) ) ). Models . ). In the following example even if “rule1” fails “rule2” will be processed and error messages for both failing rules will be returned if “rule2” also fails: public $validate = array( 'login' => array( 'rule1' => array( 'rule' => 'alphaNumeric'. 'message' => 'Only alphabets and numbers allowed'. ). 'rule2' => array( 'rule' => array('minLength'. 8). If the alphaNumeric rules fails the array key for this rule ‘Only alphabets and numbers allowed’ will be returned as error message since the message key is not set.CakePHP Cookbook Documentation. last In case of multiple rules per field by default if a particular rule fails error message for that rule is returned and the following rules for that field are not processed.x 'rule' => 'alphaNumeric'. each rule is identified with an arbitrary name. The above example defines two rules for the login field: loginRule-1 and loginRule-2. As you can see. 'loginRule-2' => array( 'rule' => array('minLength'. 'message' => 'Only alphabets and numbers allowed'.

you can always create your own validation rules. There are two ways you can do this: by defining custom regular expressions.}$/i'.x Custom Validation Rules If you haven’t found what you need thus far. $limit) { // $check will have value: array('promotion_code' => 'some-value') // $limit will have value: 25 $existingPromoCount = $this->find('count'. with a minimum of three characters. 'message' => 'This code has been used too many times. array( 'conditions' => $check. public function limitDuplicates($check. you need to add your own validation function. The example above checks if the login contains only letters and integers. Custom Regular Expression Validation If the validation technique you need to use can be completed by using regular expression matching.' ) ). you can define a custom expression as a field validation rule: public $validate = array( 'login' => array( 'rule' => '/^[a-z0-9]{3. or by creating custom validation methods. Release 2. 'recursive' => -1 )). For example. 'message' => 'Only letters and integers. The optional trailing ‘i’ after the last slash means the reg-exp is case insensitive. min 3 characters' ) ). Adding your own Validation Methods Sometimes checking data with regular expression patterns is not enough.CakePHP Cookbook Documentation. } } The current field to be validated is passed into the function as first parameter as an associated array with field name as key and posted data as value. return $existingPromoCount < $limit. 25). if you want to ensure that a promotional code can only be used 25 times. as shown below: class User extends AppModel { public $validate = array( 'promotion_code' => array( 'rule' => array('limitDuplicates'. The regular expression in the rule must be delimited by slashes. More on models 271 .

The full record being validated is stored in $this->data member variable: class Post extends AppModel { public $validate = array( 'slug' => array( 'rule' => 'alphaNumericDashUnderscore'. Model/behavior methods are checked first. $value). or at model level. which holds every rule set for each field in your model. public function alphaNumericDashUnderscore($check) { // $data array is passed using the form field name as the key // have to extract the value to make the function generic $value = array_values($check). The $check array is passed with the form field name as its key and the field value as its value. All validation rules are stored in a ModelValidator object. Models . This includes mapped methods. take care to extract the field value from the $check array. If the validation failed. The other valid return value are strings which will be shown as the error message.x If you want to pass extra parameters to your validation function. Nevertheless. dash and underscore' ) ). This means that you can override existing validation methods (such as alphaNumeric()) at an application level (by adding the method to AppModel). return preg_match('|^[0-9a-zA-Z_-]*$|'. Defining new validation rules is as easy as telling this object to store new validation methods for the fields you want to. ' numbers. before looking for a method on the Validation class. Your validation function can be in the model (as in the example above). change or remove validation rules from the predefined set. Validation methods that are The method should return true if the value is valid. $value = $value[0].' . 'message' => 'Slug can only be letters. and handle them as extra params (after the main $check param) in your function. protected and private are not supported. Release 2. Returning a string means the validation failed. add elements onto the ‘rule’ array. 272 Chapter 6. When writing a validation rule which can be used by multiple fields. there are cases when you want to dynamically add. The string will overwrite the message set in the $validate array and be shown in the view’s form as the reason why the field was not valid.CakePHP Cookbook Documentation. } } Note: Your own validation methods must have public visibility. return false. Dynamically change validation rules Using the $validate property to declare validation rules is a good way of statically defining rules for each model. or in a behavior that the model implements.

array( 'rule' => 'notBlank'. Alternatively. 8. 'required'. This will add a single rule to the password field in the model. you can use the validator object to set rules directly to fields using the array interface: $validator = $this->validator(). array( 'required' => array( 'rule' => 'notBlank'.2. 'message' => 'Password should be at least 8 chars long' )). 'required' => 'create' )). 'alphanumeric' => array( 'rule' => 'alphanumeric' ) ). The ModelValidator objects allows several ways for adding new fields to the set. 20). 'size' => array( 'rule' => array('lengthBetween'. 'required' => 'create' ). Release 2. 'size'. The first one is using the add method: // Inside a model class $this->validator()->add('password'. $validator['username'] = array( 'unique' => array( 'rule' => 'isUnique'. 'required' => 'create' )) ->add('password'. 'required' => 'create' ).CakePHP Cookbook Documentation. 8. 20).x Adding new validation rules New in version 2. You can chain multiple calls to add to create as many rules as you like: // Inside a model class $this->validator() ->add('password'. It is also possible to add multiple rules at once for a single field: $this->validator()->add('password'. array( 'rule' => 'notBlank'. 'required'. array( 'rule' => array('lengthBetween'. More on models 273 . 'message' => 'Password should be at least 8 chars long' ) )).

CakePHP Cookbook Documentation.).. 'required').. 'required' => true )). 'required' => 'create' ). array( 'rule' => 'required'. append methods to a field or completely remove a rule from a field rule set: // In a model class $this->validator()->getField('password')->setRule('required'. 274 Chapter 6. Properties in any CakeValidationRule get their name from the array keys one is allowed to use when defining a validation rule’s properties. $validator['username']['unique'] = array( 'rule' => 'isUnique'.) )). Release 2. Removing rules from the set New in version 2. Models . Modifying current validation rules is also possible using the validator object. it is also possible to modify existing rules using the array interface: $validator = $this->validator(). It is possible to both completely remove all rules for a field and to delete a single rule in a field’s rule set: // Completely remove all rules for a field $this->validator()->remove('username'). As with adding new rule to the set. // Remove 'required' rule from password $this->validator()->remove('password'.2. $validator['username']['unique']->message = 'Name already taken'. If you wish to just modify a single property in a rule you can set properties directly into the CakeValidationRule object: // In a model class $this->validator()->getField('password') ->getRule('required')->message = 'This field cannot be left blank'.. 'otherRule' => array(. $validator['username']['unique']->last = true. there are several ways in which you can alter current rules.2. You can also completely replace all the rules for a field using a similar method: // In a model class $this->validator()->getField('password')->setRules(array( 'required' => array(..x Modifying current validation rules New in version 2. such as the array keys ‘message’ and ‘allowEmpty’ for example.

Be careful that it may be larger than the number of characters when handling non-ASCII characters. public $validate = array( 'login' => array( 'rule' => 'alphaNumeric'. static Validation::lengthBetween(string $check. More on models 275 .CakePHP Cookbook Documentation. Both minimum and maximum values must be supplied. Below. The length of data is “the number of bytes in the string representation of the data”.' ) ). and newline. Uses = not. along with usage examples. you’ll find a complete list of all the rules. integer $min. tab. White space characters include space. public $validate = array( 'id' => array( 'rule' => 'blank'. 'message' => 'Passwords must be between 5 and 15 characters long. you can use the array interface to delete rules from the set: $validator = $this->validator().' ) ). This class contains many oft-used validation techniques you won’t need to write on your own. carriage return. 5. 15). 'message' => 'Usernames must only contain letters and numbers.x Optionally. 'on' => 'create' ) ). integer $max) The length of the data for the field must fall within the specified numeric range. // Remove 'required' rule from password unset($validator['password']['required']). Core Validation Rules class Validation The Validation class in CakePHP contains many validation rules that can make model data validation much easier. static Validation::blank(mixed $check) This rule is used to make sure that the field is left blank or only white space characters are present in its value. Release 2. public $validate = array( 'password' => array( 'rule' => array('lengthBetween'. static Validation::alphaNumeric(mixed $check) The data for the field must only contain letters and numbers. // Completely remove all rules for a field unset($validator['username']).

'message' => 'The credit card number you supplied was invalid. 'message' => 'Incorrect value for myCheckbox' ) ). false. array('visa'. the validation will check the Luhn algorithm of the credit card (http://en. The ‘type’ key can be assigned to the values of ‘fast’.x static Validation::boolean(string $check) The data for the field must be a boolean value. Valid values are true or false. null). It takes three parameters: ‘type’. The ‘regex’ key allows you to supply your own regular expression that will be used to validate the credit card number: public $validate = array( 'ccnumber' => array( 'rule' => array('cc'. mixed $type = ‘fast’. The ‘deep’ key should be set to a boolean value. 'maestro'). ‘all’ or any of the following: •amex •bankcard •diners •disc •electron •enroute •jcb •maestro •mc •solo •switch •visa •voyager If ‘type’ is set to ‘fast’. it validates the data against the major credit cards’ numbering formats.CakePHP Cookbook Documentation. It defaults to false. If it is set to true. boolean $deep = false.org/wiki/Luhn_algorithm). You can also set ‘type’ to an array of the types you wish to match. Setting ‘type’ to ‘all’ will check with all the credit card types. integers 0 or 1 or strings ‘0’ or ‘1’.wikipedia. static Validation::cc(mixed $check. ‘deep’ and ‘regex’. Models . Release 2. public $validate = array( 'myCheckbox' => array( 'rule' => array('boolean'). string $regex = null) This rule is used to check whether the data is a valid credit card number.' 276 Chapter 6.

static Validation::date(string $check. “is less”. 12-27-2006 or 12-27-06 (separators can be a space.' ) ). forward slash) If no keys are supplied. (December 2006 or Dec 2006) •‘my’ e. 2006 or Dec 27. period. 27 December 2006 or 27 Dec 2006 •‘Mdy’ e. forward slash) •‘mdy’ e. “greater or equal”. string $operator = null. forward slash) •‘dMy’ e. “equal to”.g. dash. period. forward slash) •‘ym’ e. period. December 27. '\u221E').g. 'message' => 'Please enter an infinite number. static Validation::custom(mixed $check. A single parameter (which can be an array) can be passed that will be used to check the format of the supplied date. Some examples are shown below: public $validate = array( 'age' => array( 'rule' => array('comparison'.g.g.g. 'greater or equal'.g. 'message' => 'Must be at least 18 years old to qualify. 2006/12 or 06/12 (separators can be a space. 12/2006 or 12/06 (separators can be a space. Release 2. dash.CakePHP Cookbook Documentation. string $regex = null) This rule ensures that data is submitted in valid date formats. dash. period. forward slash) •‘ymd’ e. period. 2006-12-27 or 06-12-27 (separators can be a space. forward slash) •‘y’ e. 2006 (comma is optional) •‘My’ e. 2006 (separators can be a space. integer $check2 = null) Comparison is used to compare numeric values.x ) ). the default key that will be used is ‘ymd’: More on models 277 . period.' ) ). string $regex = null) Used when a custom regular expression is needed: public $validate = array( 'infinite' => array( 'rule' => array('custom'. public $validate = array( 'age' => array( 'rule' => array('comparison'.g. 18). and “not equal”.' ) ). The value of the parameter can be one of the following: •‘dmy’ e. dash. 27-12-2006 or 27-12-06 (separators can be a space. dash. dash. mixed $format = ‘ymd’.g. “less or equal”. 18). 'message' => 'Must be at least 18 years old to qualify. '>='. static Validation::comparison(mixed $check1.g. It supports “is greater”.

'ymd'). If this parameter is used. 'dmy'). the default key that will be used is ‘ymd’: public $validate = array( 'birthday' => array( 'rule' => array('datetime'. 2006-12-27 or 06-12-27 (separators can be a space. December 27. 'message' => 'Please enter a valid date and time. the better. forward slash) •‘dMy’ e. forward slash) •‘mdy’ e. dash. 'allowEmpty' => true ) ). 27 December 2006 or 27 Dec 2006 •‘Mdy’ e. string $regex = null) This rule ensures that the data is a valid datetime format. forward slash) •‘ymd’ e. period.g.' ) ). rather than forcing users to supply a given format. which will cause validation to fail if no digits are found after the decimal point: public $validate = array( 'price' => array( 'rule' => array('decimal'. you might consider doing the heavy lifting by accepting a wide-array of date formats and trying to convert them. datetime() will validate a date and a time. Models . static Validation::decimal(string $check.x public $validate = array( 'born' => array( 'rule' => array('date'. forward slash) If no keys are supplied. Note that unlike date().'. dash. A parameter (which can be an array) can be passed to specify the format of the date. Release 2.4: The ym and y formats were added.g. 12-27-2006 or 12-27-06 (separators can be a space. Also a second parameter can be passed to specify a custom regular expression. 27-12-2006 or 27-12-06 (separators can be a space. dash. The value of the parameter can be one or more of the following: •‘dmy’ e.g. 'message' => 'Enter a valid date in YY-MM-DD format. the data will be validated as a scientific float.g. this will be the only validation that will occur.g. The more work you can do for your users. (December 2006 or Dec 2006) •‘my’ e. 2006 or Dec 27. static Validation::datetime(array $check.CakePHP Cookbook Documentation. period.g. A parameter can be passed to specify the number of digits required after the decimal point. dash. period. integer $places = null. period. 12/2006 or 12/06 (separators can be a space. Changed in version 2. 2006 (comma is optional) •‘My’ e. While many data stores require a certain date format.g. 2) 278 Chapter 6. mixed $dateFormat = ‘ymd’. string $regex = null) This rule ensures that the data is a valid decimal number. If no parameter is passed.

mixed $compareTo) This rule will ensure that the value is equal to. 'message' => 'This value must be the string cake' ) ). static Validation::fileSize($check. array('gif'. You can use $operator to decide the type of comparison you want to use. public $validate = array( 'food' => array( 'rule' => array('equalTo'. $operator = null. ‘jpg’)) This rule checks for valid file extensions like . '1MB'). 'cake'). This method will automatically handle array values from $_FILES by reading from the tmp_name key if $check is an array and contains that key: public $validate = array( 'image' => array( 'rule' => array('fileSize'. 'jpeg'. '<='.jpg or .png.' ) ).x ) ). static Validation::email(string $check. string $regex = null) This checks whether the data is a valid email address. More on models 279 . ‘png’.' ) ). boolean $deep = false. and of the same type as the given value. All the operators supported by comparison() are supported here as well. Allow multiple extensions by passing them in array form. static Validation::equalTo(mixed $check.CakePHP Cookbook Documentation. public $validate = array( 'image' => array( 'rule' => array( 'extension'. 'message' => 'Please supply a valid email address. ‘jpeg’. 'jpg') ). true). static Validation::extension(mixed $check. 'message' => 'Please supply a valid image. array $extensions = array(‘gif’. public $validate = array( 'email' => array( 'rule' => array('email'. 'png'. Release 2. 'message' => 'Image must be less than 1MB' ) ). $size = null) This rule allows you to check filesizes. Passing a boolean true as the second parameter for this rule will also attempt to verify that the host for the address is valid: public $validate = array('email' => array('rule' => 'email')).

array('Foo'. // or 'IPv6' or 'both' (default) 'message' => 'Please supply a valid IP address. public $validate = array( 'clientip' => array( 'rule' => array('ip'. Accepts as option ‘both’ (default). You can set $caseInsensitive to true if you need case insensitive comparison. 'Bar')). Model::isUnique() The data for the field must be unique.' ) ). You may consider marking the listed fields as required. 280 Chapter 6.' ) ). Comparison is case sensitive by default.CakePHP Cookbook Documentation. 'message' => 'Enter either Foo or Bar. array $list. You can validate that a set of fields are unique by providing multiple fields and set $or to false: public $validate = array( 'email' => array( 'rule' => array('isUnique'.' ) ). Make sure to include the original field in the list of fields when making a unique rule across multiple fields. Models . If a listed field isn’t included in the model data. string $type = ‘both’) This rule will ensure that a valid IPv4 or IPv6 address has been submitted. false). array('email'.' ) ) ).3 static Validation::inList(string $check. boolean $caseInsensitive = false) This rule will ensure that the value is in a given set. 'message' => 'This username & email combination has already been used. It needs an array of values. Release 2. ‘IPv4’ or ‘IPv6’. then it’s treated as a null value. it cannot be used by any other rows: public $validate = array( 'login' => array( 'rule' => 'isUnique'. 'IPv4').x New in version 2. 'message' => 'This username has already been taken.3: This method was added in 2. static Validation::ip(string $check. 'username'). Example: public $validate = array( 'function' => array( 'allowedChoice' => array( 'rule' => array('inList'. The field is valid if the field’s value matches one of the values in the given array.

' ).' ).5 $mimeTypes can be a regex string. '#image/. See http://en.CakePHP Cookbook Documentation. array|string $mimeTypes) New in version 2. 15). More on models 281 . Be careful that it may be larger than the number of characters when handling non-ASCII characters. integer $min) This rule ensures that the data meets a minimum length requirement. 'message' => 'Usernames must be at least 8 characters long. Release 2.5. array('image/gif')). 'message' => 'Invalid mime type. integer $max) This rule ensures that the data stays within a maximum length requirement.' ) ).wikipedia. 8). 'message' => 'Invalid mime type. 'message' => 'Usernames must be no larger than 15 characters long. boolean $deep = false) The Luhn algorithm: A checksum formula to validate a variety of identification numbers. static Validation::maxLength(string $check. static Validation::money(string $check.+#'). Be careful that it may be larger than the number of characters when handling non-ASCII characters. Since 2. 'logo' => array( 'rule' => array('mimeType'.' ) ). The length here is “the number of bytes in the string representation of the data”. string $symbolPosition = ‘left’) This rule will ensure that the value is in a valid monetary amount.x static Validation::luhn(string|array $check. static Validation::mimeType(mixed $check.2. ). Comparison is case sensitive. public $validate = array( 'image' => array( 'rule' => array('mimeType'.org/wiki/Luhn_algorithm for more information. The length here is “the number of bytes in the string representation of the data”. Changed in version 2. public $validate = array( 'login' => array( 'rule' => array('minLength'. static Validation::minLength(string $check. This rule checks for valid mime types. public $validate = array( 'login' => array( 'rule' => array('maxLength'. Second parameter defines where symbol is located (left/right).

'ti').' ) ). 're'. 'mi'. Do not use this for a multiple select input as it will cause an error. 'message' => 'Please select one. two or three options' ) ). 'sol'. public $validate = array( 'cars' => array( 'rule' => 'numeric'. 'min' => 1. 'left'). static Validation::notEmpty(mixed $check) Deprecated since version 2.x public $validate = array( 'salary' => array( 'rule' => array('money'. static Validation::notBlank(mixed $check) New in version 2. mixed $options = array().7. Release 2. 'message' => 'Please supply the number of cars.' ) ). 'message' => 'Please supply a valid monetary amount. Instead. “max” and “min”. Models .7. 'max' => 3 )). 'message' => 'This field cannot be left blank' ) ). You can set $caseInsensitive to true if you need case insensitive comparison.CakePHP Cookbook Documentation. public $validate = array( 'title' => array( 'rule' => 'notBlank'. static Validation::multiple(mixed $check. static Validation::numeric(string $check) Checks if the data passed is a valid number. 'fa'. use “multiple”. public $validate = array( 'multiple' => array( 'rule' => array('multiple'. Comparison is case sensitive by default. The basic rule to ensure that a field is not empty. 282 Chapter 6. array( 'in' => array('do'. 'la'. boolean $caseInsensitive = false) Use this for validating a multiple select input. Use notBlank instead. It supports parameters “in”.

static Validation::range(string $check. 'us') ) ). U.' ). true). public $validate = array( 'phone' => array( 'rule' => array('phone'. If you want to validate non-US phone numbers. public $validate = array( 'wheels' => array( 'rule' => 'naturalNumber'. Release 2. (us). ). 'message' => 'Please enter a number between -1 and 11' ) ).2. integer $lower = null. This rule checks if the data passed is a valid natural number. public $validate = array( 'zipcode' => array( 'rule' => array('postal'. Note: The range lower/upper are not inclusive More on models 283 .K (uk). 'message' => 'Please supply the number of airbags. static Validation::phone(mixed $check. If no range is supplied. The above example will accept any value which is larger than -1 (e. Canada (ca).CakePHP Cookbook Documentation. you can provide a regular expression as the second parameter to cover additional number formats. 11). -0.' ). 'us') ) ).x static Validation::naturalNumber(mixed $check. 'message' => 'Please supply the number of wheels.g. integer $upper = null) This rule ensures that the value is in a given range. null.99) and less than 11 (e.99). public $validate = array( 'number' => array( 'rule' => array('range'. string $country = ‘all’) Phone validates US phone numbers. the rule will check to ensure the value is a legal finite on the current platform. null. boolean $allowZero = false) New in version 2. 10. If $allowZero is set to true.g. string $regex = null. 'airbags' => array( 'rule' => array('naturalNumber'. Italy (it). string $regex = null. string $country = ‘us’) Postal is used to validate ZIP codes from the U. you may provide a regular expression as the second parameter... For other ZIP code formats.S. zero is also accepted as a value. static Validation::postal(mixed $check. -1. Germany (de) and Belgium (be).

Models . static Validation::time(string $check) Time validation. static Validation::url(string $check.2. Denmark (dk).CakePHP Cookbook Documentation. you may provide a regular expression. static Validation::userDefined(mixed $check. (us). determines if the string passed is a valid time. ). and the Netherlands (nl). string $method. Release 2. boolean $strict = false) This rule checks for valid URL formats. news. and gopher protocols: public $validate = array( 'website' => array( 'rule' => 'url' ) ). array $args = null) Runs an user-defined validation. file. To ensure that a protocol is in the url. This rule checks if a file upload has an error. null. This validation method uses a complex regular expression that can sometimes cause issues with Apache2 on Windows using mod_php. static Validation::uuid(string $check) Checks that a value is a valid UUID: http://tools. string $regex = null.' ). Supports http(s). string $country = null) Ssn validates social security numbers from the U. strict mode can be enabled like so: public $validate = array( 'website' => array( 'rule' => array('url'. object $object. 'message' => 'Something went wrong with the upload. public $validate = array( 'image' => array( 'rule' => 'uploadError'. static Validation::uploadError(mixed $check) New in version 2. For other social security number formats.S. Validates time as 24hr (HH:MM) or am/pm ([H]H:MM[a|p]m) Does not allow/validate seconds.ietf. ftp(s). 'us') ) ). true) ) ).org/html/rfc4122 284 Chapter 6. public $validate = array( 'ssn' => array( 'rule' => array('ssn'.x static Validation::ssn(mixed $check.

. something that a large switch would not have. 'nl')). which will return true if it validates and false if it doesn’t: if ($this->ModelName->validates()) { // it validated logic } else { More on models 285 . set the data to the model: $this->ModelName->set($this->request->data). 'postal_code' => array('rule' => array('postal'. Tip: The Localized Plugin already contains a lot of rules ready to use: https://github. there may be times where you wish to validate the data without saving it.. Validating Data from the Controller While normally you would just use the save method of the model. ). } public static function postal($check) { // . This approach allows you to create classes that handle a subset or group of locales. In your model validation you could use your NlValidation class by doing the following: public $validate = array( 'phone_no' => array('rule' => array('phone'.CakePHP Cookbook Documentation. the ability to pass off to another validator has been added. but must be imported via App::uses() before attempting to use it. Validating data requires a slightly different process than just saving the data.com/cakephp/localized Also feel free to contribute with your localized validation rules. Validation will see that it cannot handle the nl locale and will attempt to delegate out to NlValidation::postal() and the return of that method will be used as the pass/fail for the validation.x Localized Validation The validation rules phone() and postal() will pass off any country prefix they do not know how to handle to another class with the appropriate name. When your model data is validated. null. Then. to check if the data validates. For example if you lived in the Netherlands you would create a class like: class NlValidation { public static function phone($check) { // . use the validates method of the model. Release 2. null.. 'nl')).. First. you may wish to display some additional information to the user before actually saving the data to the database. The usage of the individual validation methods has not changed. } } This file could be placed in APP/Validation/ or App/PluginName/Validation/. For example.

These functions can be defined in model classes (including your AppModel) class. use model callbacks. the following approach should be used: if ($this->ModelName->saveAll( $this->request->data. The invalidFields method also returns that data as the result: $errors = $this->ModelName->invalidFields(). It is important to note that the data must be set to the model before the data can be validated. Also. This is different from the save method which allows the data to be passed in as a parameter. keep in mind that it is not required to call validates prior to calling save as save will automatically validate the data before actually saving. To do this you can pass an options array specifying the fields to validate: if ($this->User->validates(array('fieldList' => array('email'. Release 2. array('validate' => false) )) { // saving without validation } Callback Methods If you want to sneak in some logic just before or after a CakePHP model operation. In this instance when creating or editing a user you would want to validate all 4 field rules. Instead use validates() and access the validationErrors model property.CakePHP Cookbook Documentation. array('validate' => 'only') )) { // validates } else { // does not validate } If you have validated data before save. Yet when a user logs in you would validate just email and password rules. email and password. last_name. } It may be desirable to validate your model only using a subset of the validations specified in your model. Be sure to note the 286 Chapter 6. To validate multiple models. // contains validationErrors array The validation errors list is not cleared between successive calls to invalidFields() So if you are validating in a loop and want each set of errors separately don’t use invalidFields().x // didn't validate logic $errors = $this->ModelName->validationErrors. you can turn off validation to avoid second check: if ($this->ModelName->saveAll( $this->request->data. Models . For example say you had a User model with fields for first_name. 'password')))) { // valid } else { // invalid } The validates method invokes the invalidFields method which populates the validationErrors property of the model.

). return false. or anything you want to get passed to find and its counterparts. You might use this callback to restrict find operations based on a user’s role. fields. you may get this: $results = array( 'field_1' => 'value1'. or make caching decisions based on the current load. afterFind afterFind(array $results.x expected return values for each of these special functions. The $primary parameter indicates whether or not the current model was the model that the query originated on or whether or not this model was queried as an association. More on models 287 . beforeFind beforeFind(array $query) Called before any find-related operation. The return value for this callback should be the (possibly modified) results for the find operation that triggered this callback. return the possibly modified $query. i. boolean $primary = false) Use this callback to modify results that have been returned from a find operation. Warning: Code expecting $primary to be true will probably get a “Cannot use string offset as an array” fatal error from PHP if a recursive find is used. When using callback methods you should remember that behavior callbacks are fired before model callbacks are. If you do not wish the find operation to begin (possibly based on a decision relating to the $query options). ). 'field2' => 'value2'. 'field_2' => 'value2' ).CakePHP Cookbook Documentation. The $results parameter passed to this callback contains the returned results from the model’s find operation. Otherwise. The $query passed to this callback contains information about the current query: conditions. instead of the result you would normally get from a find operation. If a model is queried as an association the format of $results can differ. etc. ).e. something like: $results = array( 0 => array( 'ModelName' => array( 'field1' => 'value1'. or to perform any other post-find logic. Release 2.

CakePHP Cookbook Documentation. access it at $this->data and modify it. or to modify validation rules if required. but just before the data is saved. strtotime($dateString)). This function must also return true. } beforeValidate beforeValidate(array $options = array()) Use this callback to modify model data before it is validated. afterValidate afterValidate() Called after data has been checked for errors. Models . If your storage engine needs dates in a specific format. Release 2. The code in the example is used for an application with a begindate formatted like YYYY-MM-DD in the database and is displayed like DD-MM-YYYY in the application. otherwise the current save() execution will abort. Use the code below in the appropriate model. This callback is especially handy for any data-massaging logic that needs to happen before your data is stored. } public function dateFormatAfterFind($dateString) { return date('d-m-Y'. beforeSave beforeSave(array $options = array()) Place any pre-save logic in this function.x Below is an example of how afterfind can be used for date formatting: public function afterFind($results. $primary = false) { foreach ($results as $key => $val) { if (isset($val['Event']['begindate'])) { $results[$key]['Event']['begindate'] = $this->dateFormatAfterFind( $val['Event']['begindate'] ). } } return $results. This function executes immediately after model data has been successfully validated. Of course this can be changed very easily. Below is an example of how beforeSave can be used for date conversion. public function beforeSave($options = array()) { if (!empty($this->data['Event']['begindate']) && !empty($this->data['Event']['enddate']) 288 Chapter 6. Use this callback to perform any data cleanup or preparation if needed. This function should also return true if you want the save operation to continue.

afterSave afterSave(boolean $created. The saved data will be available in $this->data.php // In the following example. strtotime($dateString)). This function should return true if you want the deletion to continue. Tip: Make sure that beforeDelete() returns true. $this->data['Event']['enddate'] = $this->dateFormatBeforeSave( $this->data['Event']['enddate'] ). } public function dateFormatBeforeSave($dateString) { return date('Y-m-d'.CakePHP Cookbook Documentation. The $options array is the same one passed to Model::save(). place it in this callback method. do not let a product category be deleted if it // still contains products. beforeDelete beforeDelete(boolean $cascade = true) Place any pre-deletion logic in this function. array $options = array()) If you have logic you need to be executed just after every save operation. The value of $created will be true if a new record was created (rather than an update). and false if you want to abort. Release 2. The value of $cascade will be true if records that depend on this record will also be deleted. } Tip: Make sure that beforeSave() returns true. public function beforeDelete($cascade = true) { $count = $this->Product->find("count". or your delete is going to fail.php has set // $this->id .x ) { $this->data['Event']['begindate'] = $this->dateFormatBeforeSave( $this->data['Event']['begindate'] ). array( "conditions" => array("product_category_id" => $this->id) More on models 289 . // A call of $this->Product->delete($id) from ProductsController. // using app/Model/ProductCategory. // Assuming 'ProductCategory hasMany Product'. we can access $this->Product // in the model. } return true. or your save is going to fail.

// perhaps after deleting a record from the database. inserting. and editing rows in the table. In this section. 290 Chapter 6. translated content. As an example. } afterDelete afterDelete() Place any logic that you want to be executed after every deletion in this callback method. Release 2. consider a model that gives us access to a database table which stores structural information about a tree. we’ll cover the basic usage pattern for adding behaviors to models. or in more formal terms.org). That’s how behaviors allow models to get rid of all the extra weight that might not be part of the business contract they are modeling. CakePHP already includes behaviors for tree structures. and migrating nodes in the tree is not as simple as deleting. Rather than creating those tree-manipulation methods on a per model basis (for every model that needs that functionality). our CakePHP model takes on a whole new set of methods that allow it to interact with the underlying structure. or that is also needed in different models and can then be extrapolated. you also want to delete // an associated file public function afterDelete() { $file = new File($this->data['SomeModel']['file_path']). how to use CakePHP’s built-in behaviors. Removing. and they do this without requiring inheritance. Models . For example creating tree structures. } onError onError() Called if any problems occur. behaviors allow us to attach functionality to models by defining a simple class variable. access control list interaction. They allow us to separate and reuse logic that creates a type of behavior. } return false. $file->delete().CakePHP Cookbook Documentation. With just one line of code. we could simply tell our model to use the TreeBehavior. This is known as attaching a behavior to a model. if ($count == 0) { return true. not to mention the community-contributed behaviors already available in the CakePHP Bakery (http://bakery. and how to create our own. Behaviors Model behaviors are a way to organize some of the functionality defined in CakePHP models. Many records may need to be updated as things move around. adding.cakephp. we tell our model to behave as a Tree. By providing a simple yet powerful way to enhance models.x )).

reference the chapters below: ACL class AclBehavior The Acl behavior provides a way to seamlessly integrate a model with your ACL system. } 1 http://en. There are a number of Behaviors included in CakePHP. However. using it requires that your Model has a parentNode() method defined. If your application depends on having those models to extend AppModel for some reason. When adding it to the actsAs array you choose to make the related Acl entry an ARO or an ACO. Aco. then copy AclNode to your application and have it extend AppModel again. To find out more about each one.1: You can now safely attach AclBehavior to AppModel. array('type' => 'controlled')). The default is to create ACOs: class User extends AppModel { public $actsAs = array('Acl' => array('type' => 'requester')). } For User and Group models it is common to have both ACO and ARO nodes. To join the ACL behavior in ACO mode use: class Post extends AppModel { public $actsAs = array('Acl' => array('type' => 'controlled')). Release 2. Using the AclBehavior Most of the AclBehavior works transparently on your Model’s afterSave().CakePHP Cookbook Documentation. you can add it to the $actsAs property of your model. which would cause an infinite loop. Aro and AclNode now extend Model instead of AppModel. to achieve this use: class User extends AppModel { public $actsAs = array('Acl' => array('type' => 'both')). To use the new behavior. } You can also attach the behavior on the fly like so: $this->Post->Behaviors->load('Acl'. It can create both AROs or ACOs transparently. } This would attach the Acl behavior in ARO mode.org/wiki/Mixin More on models 291 . Changed in version 2. This is used by the AclBehavior to determine parent->child relationships. A model’s parentNode() method must return null or return a parent Model reference: public function parentNode() { return null.x In essence.wikipedia. Behaviors are Mixins1 with callbacks.

you need to specify which node type you want: $this->User->id = 1. if (empty($this->data)) { $data = $this->read(). It is important to have the id value set or the parentNode relation will fail. $node = $this->User->node(). $node = $this->User->node($user). Models . 'Aro'). You can also retrieve the Acl Node for any row. $node = $this->User->node(null. } return array('Group' => array('id' => $data['User']['group_id'])). } if (!$data['User']['group_id']) { return null. Will both return the same Acl Node information. } A more complete example. $user = array('User' => array( 'id' => 1 )). node() The AclBehavior also allows you to retrieve the Acl node associated with a model record.CakePHP Cookbook Documentation. After setting $model->id. If you had setup AclBehavior to create both ACO and ARO nodes. parentNode() must return the alias of the ACO or ARO node: public function parentNode() { return 'root_node'. by passing in a data array: $this->User->id = 1. $user = array('User' => array( 'id' => 1 292 Chapter 6. Release 2. The AclBehavior uses this data to construct its tree structure. } In the above example the return is an array that looks similar to the results of a model find.x If you want to set an ACO or ARO node as the parent for your Model. where User belongsTo Group: public function parentNode() { if (!$this->id && empty($this->data)) { return null. } $data = $this->data. You can use $model->node() to retrieve the associated Acl node. Using an example User Model.

x )). To use the new behavior. Let’s say that ‘Post’ hasMany ‘Comment’. $node = $this->User->node($user. It does this by using the supplied containments to generate a series of bindModel and unbindModel calls. increasing the speed and overall performance of your application. you can add it to the $actsAs property of your model: class Post extends AppModel { public $actsAs = array('Containable'). First.CakePHP Cookbook Documentation. [0] => Array ( [Post] => Array ( [id] => 1 [title] => First article [content] => aaa [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( [0] => Array ( [id] => 1 More on models 293 . Release 2. The amount of data fetched in a normal find() call is rather extensive: debug($this->Post->find('all')). we’ll start off with a find() call on a model named ‘Post’. This model behavior allows you to filter and limit model find operations. Using Containable To see how Containable works. Containable allows you to streamline and simplify operations on your model bindings.2 core is the ContainableBehavior. let’s look at a few examples. } You can also attach the behavior on the fly: $this->Post->Behaviors->load('Containable'). Using Containable will help you cut down on needless wear and tear on your database. Containable class ContainableBehavior A new addition to the CakePHP 1. 'Aro'). Since Containable only modifies existing relationships it will not allow you to restrict results by distant associations. and ‘Post’ hasAndBelongsToMany ‘Tag’. The class will also help you search and filter your data for your users in a clean and consistent way. Instead you should refer to Joining tables. It works by temporarily or permanently altering the associations of your models.

. Having done that.x [post_id] => 1 [author] => Daniel [email] => dan@example.com [website] => http://example. you can do the following: $this->Post->contain().. Release 2.net [website] => http://example. to get only the post-related information. Models . One thing the ContainableBehavior does is help you cut down on what find() returns. you end up with something a lot more concise: [0] => Array ( [Post] => Array 294 Chapter 6.com [comment] => First comment [created] => 2008-05-18 00:00:00 ) [1] => Array ( [id] => 2 [post_id] => 1 [author] => Sam [email] => sam@example. you may not need that much information from the Post model. You can also invoke Containable’s magic from inside the find() call: $this->Post->find('all'. For some interfaces in your application. For example.net [comment] => Second comment [created] => 2008-05-18 00:00:00 ) ) [Tag] => Array ( [0] => Array ( [id] => 1 [name] => Awesome ) [1] => Array ( [id] => 2 [name] => Baking ) ) ) [1] => Array ( [Post] => Array (. array('contain' => false)). $this->Post->find('all').CakePHP Cookbook Documentation.

but not when you want to pick and choose what to keep at each level. The contain method’s first argument accepts the name. If you look at the results of the original find() call. The model’s $recursive property is helpful if you want to hack off an entire level of recursion. or an array of names. Containable creates a cleaner way to accomplish this same task. Without Containable.CakePHP Cookbook Documentation. Again. Release 2. array('contain' => 'Tag')). Let’s see how it works by using the contain() method. multiple times if you’re paring off multiple models. If you are interested in the posts and the names of the comment authors — and nothing else — you could do something like the following: More on models 295 . $this->Post->find('all').x ( [id] => 1 [title] => First article [content] => aaa [created] => 2008-05-18 00:00:00 ) ) [1] => Array ( [Post] => Array ( [id] => 2 [title] => Second article [content] => bbb [created] => 2008-05-19 00:00:00 ) ) This sort of help isn’t new: in fact. you can do that without the ContainableBehavior doing something like this: $this->Post->recursive = -1. and you want to pare down things that sit at the same level. of the models to keep in the find operation. you’d end up needing to use the unbindModel() method of the model. we’d try something like this: $this->Post->contain('Tag'). $this->Post->find('all'). If we wanted to fetch all posts and their related tags (without any comment information). notice the author field in the Comment model. Containing deeper associations Containable also goes a step deeper: you can filter the data of the associated models. we can use the contain key inside a find() call: $this->Post->find('all'. Containable really shines when you have complex associations.

.author = "Daniel"')). we’ve told Containable to give us our post information.x $this->Post->contain('Comment. array('contain' => 'Comment.author'). //or.. $this->Post->find('all'). Models . and just the author field of the associated Comment model. Release 2. This gives us a result that gives us posts with comments authored by Daniel: [0] => Array ( [Post] => Array ( 296 Chapter 6.author')). array('contain' => 'Comment..author = "Daniel"'). $this->Post->find('all'. the Comment arrays only contain the author field (plus the post_id which is needed by CakePHP to map the results). You can also filter the associated Comment data by specifying a condition: $this->Post->contain('Comment. As you can see. Here. $this->Post->find('all'.. // or. $this->Post->find('all')..CakePHP Cookbook Documentation. The output of the find call might look something like this: [0] => Array ( [Post] => Array ( [id] => 1 [title] => First article [content] => aaa [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( [0] => Array ( [author] => Daniel [post_id] => 1 ) [1] => Array ( [author] => Sam [post_id] => 1 ) ) ) [1] => Array (.

assume you had 3 posts in your database and Daniel had commented on 2 of those posts. The operation $this->Post->find(‘all’. just comments by Daniel.com [website] => http://example. In the previous example. It won’t return all comments however.com [comment] => First comment [created] => 2008-05-18 00:00:00 ) ) ) [1] => Array ( [Post] => Array ( More on models 297 .com [website] => http://example.author = “Daniel”’)). [0] => Array ( [Post] => Array ( [id] => 1 [title] => First article [content] => aaa [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( [0] => Array ( [id] => 1 [post_id] => 1 [author] => Daniel [email] => dan@example. Release 2. array(‘contain’ => ‘Comment. would return ALL 3 posts. not just the 2 posts that Daniel had commented on.x [id] => 1 [title] => First article [content] => aaa [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( [0] => Array ( [id] => 1 [post_id] => 1 [author] => Daniel [email] => dan@example.com [comment] => First comment [created] => 2008-05-18 00:00:00 ) ) ) There is an important caveat to using Containable when filtering on a deeper association.CakePHP Cookbook Documentation.

created DESC' ) ))).x [id] => 2 [title] => Second article [content] => bbb [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( ) ) [2] => Array ( [Post] => Array ( [id] => 3 [title] => Third article [content] => ccc [created] => 2008-05-18 00:00:00 ) [Comment] => Array ( [0] => Array ( [id] => 22 [post_id] => 3 [author] => Daniel [email] => dan@example.author =' => "Daniel").CakePHP Cookbook Documentation. 'contain' => 'Post' )). array( 'conditions' => 'Comment. array('contain' => array( 'Comment' => array( 'conditions' => array('Comment. $this->Comment->find('all'.author = "Daniel"'. Let’s consider the following model associations: 298 Chapter 6. Additional filtering can be performed by supplying the standard find options: $this->Post->find('all'. so that posts without a comment by Daniel won’t be returned.com [website] => http://example.com [comment] => Another comment [created] => 2008-05-18 00:00:00 ) ) ) If you want to filter the posts by the comments. Here’s an example of using the ContainableBehavior when you’ve got deep and complex model relationships. the easiest way is to find all the comments by Daniel and contain the Posts. Models . Release 2. 'order' => 'Comment.

CakePHP Cookbook Documentation. array( 'contain' => array( 'Profile'. 'note') ) ) ). 'Post' => array( 'PostAttachment' => array( 'fields' => array('id'. The settings allow you to fine tune the behavior of Containable and work with other behaviors more easily. optional) set to true to allow containable to automatically determine the recursiveness level needed to fetch specified models. setting it to false disables this feature. • notices (boolean. and set the model recursiveness to this level. 'Account' => array( 'AccountSummary' ). 'name'). you may consider attaching it to your AppModel.x User->Profile User->Account->AccountSummary User->Post->PostAttachment->PostAttachmentHistory->HistoryNotes User->Post->Tag This is how we retrieve the above associations with Containable: $this->User->find('all'. The default value is true. • recursive (boolean. optional) auto-add needed fields to fetch requested bindings. • autoFields: (boolean. 'PostAttachmentHistory' => array( 'HistoryNotes' => array( 'fields' => array('id'. The default value is true. 'Tag' => array( 'conditions' => array('Tag. optional) issues E_NOTICES for bindings referenced in a containable call that are not valid. Keep in mind that contain key is only used once in the main model.be careful to include all foreign keys that your query directly or indirectly requires.name LIKE' => '%happy%') ) ) ) )). Release 2. Note: When using ‘fields’ and ‘contain’ options . you don’t need to use ‘contain’ again for related models. Please also note that because Containable must to be attached to all models used in containment. More on models 299 . The default value is true. ContainableBehavior options The ContainableBehavior has a number of options that can be set when the Behavior is attached to a model.

'Account').username' ). $this->Post->Behaviors->load('Containable'. try disabling the autoFields setting. $users = $this->paginate('User'). In this section. If you get invalid SQL errors due to mixing of aggregate and nonaggregate fields. $users = $this->paginate('User').CakePHP Cookbook Documentation. it will not honor Containable’s recursive option. 'Post' => array( 'order' => 'Post. Using Containable with pagination By including the ‘contain’ parameter in the $paginate property it will apply to both the find(‘count’) and the find(‘all’) done on the model. Translate class TranslateBehavior TranslateBehavior is actually quite easy to setup and works out of the box with very little configuration. You can change ContainableBehavior settings at run time by reattaching the behavior as seen in Behaviors (Using Behaviors). So if you set recursive to -1 for example for the model. 'order' => 'User. $this->User->contain(array('Profile'. you will learn how to add and setup the behavior to use in any model. Here’s an example of how to contain associations when paginating: $this->paginate['User'] = array( 'contain' => array('Profile'.x • order: (string. 300 Chapter 6. array('autoFields' => false)). array( 'contain' => array( 'Profile'. it won’t work: $this->User->recursive = -1.updated DESC' ) ) )). optional) the order of how the contained elements are sorted. Models . 'Account')). ContainableBehavior can sometimes cause issues with other behaviors or queries that use aggregate functions and/or GROUP BY statements. this is an example of how to force the posts to be ordered by the date when they were last updated: $this->User->find('all'. Release 2. From the previous example. See the section Using Containable for further details. Note: If you contained the associations through the model instead.

Answer with yes if you are sure there is no i18n table already. Great! According to our current example the model should now look something like this: class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'title' ) ). } This will do nothing yet. class Post extends AppModel { public $actsAs = array( 'Translate' ). Release 2. 'and_so_on' ) ). . Initializing the i18n Database Tables You can either use the CakePHP console or you can manually create it. and answer with yes again to create the table. } More on models 301 . } After you have done that (for example putting “title” as one of the fields) you already finished the basic setup. Sticking to the console will make sure that you have the correct layout. You need to define which fields of the current model should be tracked in the translation table we’ve created in the first step. because it might happen that the layout changes in future versions of CakePHP.x If you are using TranslateBehavior in alongside containable issue. It is advised to use the console for this. be sure to set the ‘fields’ key for your queries. like so: class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'fieldOne'. 'fieldTwo'.CakePHP Cookbook Documentation. Otherwise you could end up with invalid SQL generated./cake i18n Select [I] which will run the i18n database initialization script. You will be asked if you want to drop any existing and if you want to create it. because it expects a couple of options before it begins to work. Attaching the Translate Behavior to your Models Add it to your model by using the $actsAs property like in the following example. Defining the Fields You can set the fields by simply extending the ’Translate’ value with another array.

Models . Reading translated content By default the TranslateBehavior will automatically fetch and add in data based on the current locale. Release 2.CakePHP Cookbook Documentation. be sure to omit those fields from the translated model’s schema. so to speak. // $results will contain the spanish translation. Conclusion From now on each record update/creation will cause TranslateBehavior to copy the value of “title” to the translation table (default: i18n) along with the current locale. } With this setup the result of $this->Post->find() should look something like this: Array ( [Post] => Array ( [id] => 1 302 Chapter 6.x When defining fields for TranslateBehavior to translate. Retrieve all translation records for a field If you want to have all translation records attached to the current model record you simply extend the field array in your behavior setup as shown below. $results = $this->Post->find('first'. $this->Post->locale = 'es'. The naming is completely up to you. array( 'conditions' => array('Post. The current locale is read from Configure::read(’Config.id' => $id) )). If you leave the fields in. Retrieve translated fields in a specific locale By setting $Model->locale you can read translations for a specific locale: // Read the spanish locale data. there can be issues when retrieving data with fallback locales. class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'title' => 'titleTranslation' ) ). You can override this default on the fly using $Model->locale. Note: If all the fields in your model are translated be sure to add created and modified columns to your table.language’) which is assigned by the L10n class. CakePHP requires at least one non primary key field before it will save a record. A locale is the identifier of the language.

Release 2. [locale] => de_de ) [titleTranslation] => Array ( [0] => Array ( [id] => 1 [locale] => en_us [model] => Post [foreign_key] => 1 [field] => title [content] => Example entry ) [1] => Array ( [id] => 2 [locale] => de_de [model] => Post [foreign_key] => 1 [field] => title [content] => Beispiel Eintrag ) ) ) Note: The model record contains a virtual field called “locale”.CakePHP Cookbook Documentation. It indicates which locale is used in this result. using the bindTranslation method TranslateBehavior::bindTranslation($fields. With this setup the result of your find() should look something like this: Array ( More on models 303 . Models attached via associations won’t be translated because triggering callbacks on associated models is currently not supported. $this->Post->find('all'. only when you need them.. Using the bindTranslation method You can also retrieve all translations. Note that only fields of the model you are directly doing ‘find‘ on will be translated. where the key is the translatable field and the value is the fake association name. array('recursive' => 1)). // need at least recursive 1 for this to work.x [title] => Beispiel Eintrag [body] => lorem ipsum. $reset) $fields is a named-key array of field and association name.. $this->Post->bindTranslation(array('title' => 'titleTranslation')).

. $this->Post->create(). [locale] => de_de ) [titleTranslation] => Array ( [0] => Array ( [id] => 1 [locale] => en_us [model] => Post [foreign_key] => 1 [field] => title [content] => Example entry ) [1] => Array ( [id] => 2 [locale] => de_de [model] => Post [foreign_key] => 1 [field] => title [content] => Beispiel Eintrag ) ) ) Saving in another language You can force the model which is using the TranslateBehavior to save in a language other than the one detected. Example A: In your controller: class PostsController extends AppController { public function add() { if (!empty($this->request->data)) { // we are going to save the german version $this->Post->locale = 'de_de'. if ($this->Post->save($this->request->data)) { 304 Chapter 6. You can do that either in your controller or you can define it directly in the model. Release 2. Models ..CakePHP Cookbook Documentation. To tell a model in what language the content is going to be you simply change the value of the $locale property on the model before you save the data to the database.x [Post] => Array ( [id] => 1 [title] => Beispiel Eintrag [body] => lorem ipsum.

To do so you need to setup your model like this: class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'title' ) ).CakePHP Cookbook Documentation. // Option 2) create a simple method public function setLanguage($locale) { $this->locale = $locale. } } Multiple Translation Tables If you expect a lot entries you probably wonder how to deal with a rapidly growing database table. There are two properties introduced by TranslateBehavior that allow to specify which “Model” to bind as the model containing the translations. // Option 1) just define the property directly public $locale = 'en_us'. Lets say we want to save our translations for all posts in the table “post_i18ns” instead of the default “i18n” table. } Note: It is important that you to pluralize the table. To make sure it fits one could just initialize a empty i18n table using the console and rename the table afterwards. // Use a different model (and table) public $translateModel = 'PostI18n'. It is now a usual model and can be treated as such and thus comes with the conventions involved. These are $translateModel and $translateTable. More on models 305 . } } } } Example B: In your model: class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'title' ) ).x return $this->redirect(array('action' => 'index')). Release 2. The table schema itself must be identical with the one generated by the CakePHP console script.

For small trees of data. Release 2. // important } // filename: PostI18n. Reason is that there is no property to set the displayField directly in the model using this behavior yet. // Use a different table for translateModel public $translateTable = 'post_translations'. You can also add all other model stuff here like $useTable. like so: class Post extends AppModel { public $actsAs = array( 'Translate' => array( 'title' ) ).sitepoint.). This is where the optional $translateTable comes into play. class PostI18n extends AppModel { public $displayField = 'field'.CakePHP Cookbook Documentation. Make sure that you change the $displayField to ’field’. If you don’t intend to use a custom $translateModel then leave this property untouched.php That’s all it takes. data related to a multilevel menu system or a literal representation of hierarchy such as is used to store access control objects with ACL logic. is a powerful behavior which allows you to use the benefits of MPTT logic2 without worrying about any of the intricacies of the technique . // Use a different model public $translateModel = 'PostI18n'. Tree class TreeBehavior It’s fairly common to want to store hierarchical data in a database table. Examples of such data might be categories with unlimited subcategories. But for better consistency we could do that in the model which actually uses this translation model.unless you want to . Models . } Please note that you can’t use $translateTable alone. Bundled with cake however.com/hierarchical-data-database-2/ 306 Chapter 6. Reason is that it would break your setup and show you a “Missing Table” message for the default I18n model which is created in runtime. Changing the Table If you want to change the name of the table you simply define $translateTable in your model.x Create the TranslateModel For this to work you need to create the actual model file in your models folder. 2 http://www. or where the data is only a few levels deep it is simple to add a parent_id field to your database table and use this to keep track of which item is the parent of what.

`name`. 5). INSERT INTO `categories` (`id`. `parent_id`. VALUES (4. 6.default fieldname is lft. rght INTEGER(10) DEFAULT NULL. `rght`) `lft`. `name`. 1. INSERT INTO `categories` (`id`. 3. `rght`) `lft`. 3. 30). 15). Release 2. parent_id INTEGER(10) DEFAULT NULL.create the following database table and put some data in it: CREATE TABLE categories ( id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT.such as finding direct children. `parent_id`. `rght`) `lft`. to store the rght value of the current row. `name`. Note: The parent field must be able to have a NULL value! It might seem to work if you just give the top elements a parent value of zero. Basic Usage The tree behavior has a lot packed into it. `name`. INSERT INTO `categories` (`id`. PRIMARY KEY (id) ). to store the lft value of the current row. • right . `rght`) `lft`. INSERT INTO `categories` (`id`.default fieldname is parent_id. More on models `lft`. If you are familiar with MPTT logic you may wonder why a parent field exists . 3. `rght`) `lft`. VALUES (3. `parent_id`. 1. 'Surfing'.quite simply it’s easier to do certain tasks if a direct parent link is stored on the database . name VARCHAR(255) DEFAULT ''. `parent_id`. VALUES (5. but let’s start with a simple example . 7).default fieldname is rght. NULL. INSERT INTO `categories` (`id`. 'Fun'. INSERT INTO `categories` (`id`. `name`. 8). `rght`) 307 . `name`. `parent_id`. `parent_id`. 'Extreme knitting'.x Requirements To use the tree behavior. to store the id of the parent object • left . but reordering the tree (and possible other operations) will fail. 2. 4.CakePHP Cookbook Documentation. VALUES (2. 2. 'My Categories'. VALUES (1. 'Sport'. your database table needs 3 fields as listed below (all are ints): • parent . lft INTEGER(10) DEFAULT NULL.

VALUES (15. INSERT INTO `categories` (`id`. INSERT INTO `categories` (`id`. `name`. 13. 'Reports'. INSERT INTO `categories` (`id`. 'National'. 27). 19). VALUES (7. 16. INSERT INTO `categories` (`id`. 13. 10. VALUES (13.x VALUES (6. 'International'. 22). 20. `parent_id`.&nbsp. `name`. 18.' ). `rght`) `lft`. 23. 14). INSERT INTO `categories` (`id`. 29). 11). `rght`) `lft`. INSERT INTO `categories` (`id`. 6. 9. `parent_id`. VALUES (9. VALUES (11. 10. null. 21). 13). 'Gwendolyn'. 'Friends'. die. `name`. 'Gerald'. `rght`) `lft`. `parent_id`. we can create a test method and output the contents of our category tree to see what it looks like. INSERT INTO `categories` (`id`. INSERT INTO `categories` (`id`. With a simple controller: class CategoriesController extends AppController { public function index() { $data = $this->Category->generateTreeList( null.CakePHP Cookbook Documentation. `parent_id`. `name`. Release 2. 'Status'. `name`. 2. INSERT INTO `categories` (`id`. `parent_id`. `parent_id`. 6. `rght`) For the purpose of checking that everything is setup correctly. `name`. 12. 'Annual'. 28). `name`. 'Work'. debug($data). `rght`) `lft`. `name`. `parent_id`. 26. null. Models . 25).&nbsp. 9. 24. 17. VALUES (10. `rght`) `lft`. 'Trips'. 9. `parent_id`. } 308 Chapter 6. `lft`. 1. `rght`) `lft`. VALUES (12. `rght`) `lft`. '&nbsp. 10. `rght`) `lft`. `parent_id`. VALUES (8. `name`. VALUES (14.

php class Category extends AppModel { public $actsAs = array('Tree'). } We can check what our category tree data looks like by visiting /categories You should see something like this: • My Categories – Fun * Sport · Surfing · Extreme knitting * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International Adding data In the previous section. usually you would add your data in exactly the same way as you would for any model. $this->Category->save($data). and the tree behavior will take care of the rest. the tree behavior will add to the tree making your new addition a new top level entry: More on models 309 . we used existing data and checked that it looked hierarchal via the method generateTreeList. If you don’t set the parent_id. For example: // pseudo controller code $data['Category']['parent_id'] = 3.CakePHP Cookbook Documentation. However. Release 2. $data['Category']['name'] = 'Skating'.x } and an even simpler model definition: // app/Model/Category. When using the tree behavior it’s not necessary to do any more than set the parent_id.

$data['Category']['name'] = 'Other People\'s Categories'. // id of Extreme knitting $this->Category->save(array('name' => 'Extreme fishing')).CakePHP Cookbook Documentation.x // pseudo controller code $data = array(). but do not change the parent_id field . neither does the data structure. For example: // pseudo controller code $this->Category->id = 5.even if the parent_id is included in the data that is passed to save if the value doesn’t change. Therefore the tree of data would now look like: • My Categories – Fun * Sport · Surfing 310 Chapter 6. $this->Category->save($data).the structure of your data will remain unchanged. Release 2. The above code did not affect the parent_id field . Models . If you modify something. Running the above two code snippets would alter your tree as follows: • My Categories – Fun * Sport · Surfing · Extreme knitting · Skating New * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International • Other People’s Categories New Modifying data Modifying data is as transparent as adding new data.

CakePHP Cookbook Documentation. Let’s say that Extreme fishing does not belong under Sport. As would be expected the structure would be modified to: • My Categories – Fun * Sport · Surfing · Skating * Friends · Gerald · Gwendolyn – Work * Reports · Annual More on models 311 . $this->Category->save(array('parent_id' => $newParentId)). // id of Extreme fishing $newParentId = $this->Category->field( 'id'. but instead should be located under Other People’s Categories. Release 2. With the following code: // pseudo controller code $this->Category->id = 5.x · Extreme fishing Updated · Skating * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International • Other People’s Categories Moving data around in your tree is also a simple affair. array('name' => 'Other People\'s Categories') ).

let’s say that the reports category is no longer useful. For example with the following code: // pseudo controller code $this->Category->id = 10. you may get undesirable results. In addition to the core find methods.CakePHP Cookbook Documentation. To start with the simplest example. 312 Chapter 6. $this->Category->delete(). Release 2. If you call find() and do not order by lft. The category tree would be modified as follows: • My Categories – Fun * Sport · Surfing · Skating * Friends · Gerald · Gwendolyn – Work * Trips · National · International • Other People’s Categories – Extreme fishing Querying and using your data Using and manipulating hierarchical data can be a tricky business. Note: Most tree behavior methods return and rely on data being sorted by the lft field. with the tree behavior there are a few more tree-orientated permutations at your disposal. To remove it and any children it may have just call delete as you would for any model. or call a tree behavior method and pass a sort order.x · Status * Trips · National · International • Other People’s Categories – Extreme fishing Moved Deleting data The tree behavior provides a number of ways to manage deleting data. Models .

// a flat array with 11 items // Only return direct children $directChildren = $this->Category->children(1.CakePHP Cookbook Documentation. // a flat array with 11 items // -. $directChildren = $this->Category->childCount(). // will output 11 // -. // a flat array with // 2 items Note: If you want a recursive array use find(’threaded’) childCount($id = null. Using the example data from the previous section: $totalChildren = $this->Category->childCount(1). The second optional parameter defines whether or not only direct children should be returned. childCount takes the primary key value (the id) of a row and returns how many children it has. $limit = null.or -$this->Category->id = 1. $recursive=null) More on models 313 . The second optional parameter defines whether or not only direct children are counted. $fields = null. $valuePath=null. $direct = false. by default in the order they appear in the tree. $spacer= ‘_’. Release 2. $page = 1. // will output 11 // Only counts the direct descendants of this category $numChildren = $this->Category->childCount(1. $order = null. true). $recursive = null) Parameters • $id – The ID of the record to look up • $direct – Set to true to return only the direct descendants • $fields – Single string field name or array of fields to include in the return • $order – SQL string of ORDER BY conditions • $limit – SQL LIMIT statement • $page – for accessing paged results • $recursive – Number of levels deep for recursive associated Models The children method takes the primary key value (the id) of a row and returns the children. $allChildren = $this->Category->children(). $keyPath=null. $direct = false) As with the method children. // will output 2 generateTreeList($conditions=null.or -$this->Category->id = 1. true).x class TreeBehavior children($id = null. Using the example data from the previous section: $allChildren = $this->Category->children(1).

Models . "___Gerald". Parameters • $results – Results of a find(‘all’) call. Supported options are: •keyPath: A string path to the key.e. "__Trips".Post. "___Surfing". • $spacer – The string to use in front of each item to indicate depth.Post. "___National". • $options – Options to pass into. "__Sport". "_Work". i. •valuePath: A string path to the value.CakePHP Cookbook Documentation. "_Fun". i. "___International". 314 Chapter 6. Output: array( [1] => [2] => [3] => [4] => [16] => [6] => [7] => [8] => [9] => [13] => [14] => [15] => [17] => [5] => ) "My Categories". • $recursive – The number of levels deep to fetch associated records This method will return data similar to find(‘list’) but with a nested prefix that is specified in the spacer option to show the structure of your data. •spacer: The character or characters which will be repeated. "Other People's Categories". This method will return data similar to find(‘list’) but with a nested prefix that is specified in the spacer option to show the structure of your data. • $valuePath – Path to the field to use for the label. $options=array()) New in version 2.x Parameters • $conditions – Uses the same conditional options as find(). • $keyPath – Path to the field to use for the key.title”. Release 2. "__Friends". "___Gwendolyn". "___Skating". "_Extreme fishing" formatTreeList($results. “{n}. Below is an example of what you can expect this method to return: $treelist = $this->Category->generateTreeList().7. “{n}.e.id”.

. Release 2. . 'name' => 'Trips'... 'name' => 'Work'. $recursive = null) The ‘path’ when referring to hierarchal data is how you get from where you are to the top. 'name' => 'International'.id for fun // $parent contains All categories getPath($id = null.) => 13.) 315 .. [2] => array( 'Category' => array('id' ). return the parent node for any node. . or false if the node has no parent (it’s the root node). $results = $this->Category->formatTreeList($results. $fields = null. [3] => array( 'Category' => array('id' ). getParentNode() This convenience function will. as the name suggests. *International Using the id of “International” getPath will return each of the parents in turn (starting from the top)..CakePHP Cookbook Documentation.. 'name' => 'My Categories'...x An example would be: $results = $this->Category->find('all'). ) More on models => 1.) => 9. //<. [1] => array( 'Category' => array('id' ). For example: $parent = $this->Category->getParentNode(2). $parents = $this->Category->getPath(15). So for example the path from the category “International” is: •My Categories –. // contents of $parents array( [0] => array( 'Category' => array('id' ). .. –Work –Trips *. array( 'spacer' => '--' )).) => 15.

'moved down. All child nodes for the specified node will also be moved. Release 2. TreeBehavior::moveDown() Used to move a single node down the tree. if (!$this->Category->exists()) { throw new NotFoundException(__('Invalid category')). if (!$this->Category->exists()) { throw new NotFoundException(__('Invalid category')). $delta = null) { $this->Category->id = $id. You need to provide the ID of the element to be moved and a positive number of how many positions the node should be moved down.x Advanced Usage The tree behavior doesn’t only work in the background.' ). } else { $this->Session->setFlash( 'Please provide a number of positions the category should' . } if ($delta > 0) { $this->Category->moveUp($this->Category->id. Here is an example of a controller action (in a controller named Categories) that moves a specified node down the tree: public function movedown($id = null. } else { $this->Session->setFlash( 'Please provide the number of positions the field should be' . if you’d like to move the “Sport” ( id of 3 ) category one position down. 316 Chapter 6. All child nodes will also be moved. } For example. $delta = null) { $this->Category->id = $id. Models . there are a number of specific methods defined in the behavior to cater for all your hierarchical data needs.CakePHP Cookbook Documentation. TreeBehavior::moveUp() Used to move a single node up the tree. and any unexpected problems that might arise in the process. } return $this->redirect(array('action' => 'index')). You need to provide the ID of the element to be moved and a positive number of how many positions the node should be moved up. abs($delta)). abs($delta)). Here’s an example of a controller action (in a controller named Categories) that moves a node up the tree: public function moveup($id = null. } if ($delta > 0) { $this->Category->moveDown($this->Category->id. you would request: /categories/movedown/3/1.

Taking the following tree as a starting point: • My Categories – Fun * Sport · Surfing · Extreme knitting · Skating Running the following code with the id for ‘Sport’: $this->Node->removeFromTree($id). If however the following code snippet was used with the id for ‘Sport’: $this->Node->removeFromTree($id. if you would like to move the category “Gwendolyn” ( id of 8 ) up one position you would request /categories/moveup/8/1. It offers more control than delete. Release 2. Gerald.x 'be moved up. } return $this->redirect(array('action' => 'index')).' ). } For example. The Sport node will be become a top level node: • My Categories – Fun * Surfing * Extreme knitting * Skating • Sport Moved This demonstrates the default behavior of removeFromTree of moving the node to have no parent. which for a model using the tree behavior will remove the specified node and all of its children. Now the order of Friends will be Gwendolyn. true). which will be reparented one level higher.CakePHP Cookbook Documentation. The tree would become • My Categories More on models 317 . $delete = false) Using this method will either delete or move a node but retain its sub-tree. TreeBehavior::removeFromTree($id = null. and re-parenting all children.

default: true 'verify' => )).x – Fun * Surfing * Extreme knitting * Skating This demonstrates the alternate use for removeFromTree. Models . Note: If you have saved your data or made other operations on the model. Data Integrity Due to the nature of complex self referential data structures such as trees and linked lists. TreeBehavior::recover($mode = ‘parent’. they can occasionally become broken by a careless call. you might want to set $model->id = null before calling reorder. This method does not change the parent of any node. Take heart. default: 'ASC' 'order' => . $missingParentAction = null) The mode parameter is used to specify the source of info that is valid/correct. $model->reorder(array( //id of record to use as top node for reordering. E. //whether or not to verify the tree before reorder. for all is not lost! The Tree Behavior contains several previously undocumented features designed to recover from such situations. //which field to use in reordering.use the existing parent_id‘s to update the lft and rght fields • ’tree’ . TreeBehavior::reorder(array(‘id’ => null.CakePHP Cookbook Documentation. default: $Model->displayField 'field' => . Otherwise only the current node and it’s children will be reordered. default: $Model->id 'id' => . ‘field’ => $Model->displayField. The opposite source of data will be populated based upon that source of info. the children have been reparented and ‘Sport’ has been deleted. ‘order’ => ‘ASC’.g. Available $mode options: • ’parent’ . if the MPTT fields are corrupt or empty. The missingParentAction parameter only applies to “parent” mode and determines what to do if the parent field contains an id that is not present. ‘verify’ => true)) Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters. Release 2. with the $mode ’parent’ the values of the parent_id field will be used to populate the left and right fields. //direction to order.use the existing lft and rght fields to update parent_id Available missingParentActions options when using mode=’parent’: 318 Chapter 6.

default is the displayField for the model. 'verify' => true ) TreeBehavior::verify() Returns true if the tree is valid otherwise an array of errors. incorrect index and message. id.CakePHP Cookbook Documentation.’ASC’ for ascending. • ’message’ depends on the error Example Use: More on models 319 .x • null . TreeBehavior::reorder($options = array()) Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters. all of which are optional: array( 'id' => null. however the following options can affect the process: • ’id’ .whether or not to verify the tree prior to resorting. and has the following possible keys by default. • ’verify’ .do nothing and return • ’delete’ . $options is used to pass all extra parameters. // Rebuild all the parent_id's based on the lft and rght fields $this->Category->recover('tree'). • ’field‘ .delete the node • int . with fields for type. 'order' => 'ASC'.field to use for sorting. This method does not change the parent of any node.set the parent_id to this id Example: // Rebuild all the left and right fields based on the parent_id $this->Category->recover(). Release 2. 'field' => $model->displayField. Reordering affects all nodes in the tree by default. message) • type is either ’index’ or ’node’ • ’id’ is the id of the erroneous node. • ’order’ . // or $this->Category->recover('parent').do nothing and carry on • ’return’ .only reorder nodes below this node. Each record in the output array is an array of the form (type. ’DESC’ for descending sort.

no level saving )). when generating menus. you can use this method to get level of a particular node. You can use the level option to specify the field that will save level of each node: public $actAs = array('Tree' => array( 'level' => 'level'. Release 2.7.7.CakePHP Cookbook Documentation. // Defaults to null.g. If you are not caching the level of nodes using the level option in settings. TreeBehavior::getLevel($id) New in version 2. Models . i.e. Knowing the depth of tree nodes can be useful when you want to retrieve nodes only upto a certain level for e. Example output: Array ( [0] => Array ( [0] => [1] => [2] => ) [1] => Array ( [0] => [1] => [2] => ) [10] => Array ( [0] => [1] => [2] => ) [99] => Array ( [0] => [1] => [2] => ) ) node 3 left and right values identical node 2 The parent node 999 doesn't exist index 123 missing node 163 left greater than right Node Level (Depth) New in version 2. 320 Chapter 6.x $this->Category->verify().

instead. we tell our TreeBehavior the names of the “left” and “right” fields in the underlying database table: class Category extends AppModel { public $actsAs = array('Tree' => array( 'left' => 'left_node'. for example. we may need to “detach” behaviors from our models at runtime. } So far we have been adding behaviors to models using a model class variable. use the methods added by the behavior as if they always existed as part of the original model: // Set ID $this->Category->id = 42. it may also need internationalization support: class Category extends AppModel { public $actsAs = array( 'Tree' => array( 'left' => 'left_node'. we are looking to disable the behavior from acting upon our CakePHP model callbacks. we need for some reason to force it to stop acting as a Translate model: // Detach a behavior from our model: $this->Category->Behaviors->unload('Translate'). 'right' => 'right_node' ). } We can also attach several behaviors to a model. That means that our behaviors will be attached to our models throughout the model’s lifetime. which is acting as a Tree and a Translate model. } This example shows how a Category model could be managed in a tree structure using the TreeBehavior. we then tell our model to stop informing of these callbacks to the Translate behavior: More on models 321 . Instead of detaching the behavior. That will make our Category model stop behaving as a Translate model from thereon. Here. 'right' => 'right_node' )).CakePHP Cookbook Documentation. Release 2. However. We may need. 'Translate' ). Some behaviors may require or allow settings to be defined when the behavior is attached to the model. our saves. Once a behavior has been specified. // Use behavior method. to just disable the Translate behavior from acting upon our normal model operations: our finds. Let’s say that on our previous Category model. There’s no reason why. children(): $kids = $this->Category->children(). our Category model should only behave as a tree. In fact.x Using Behaviors Behaviors are attached to models through the $actsAs model class variable: class Category extends AppModel { public $actsAs = array('Tree'). etc.

x // Stop letting the behavior handle our model callbacks $this->Category->Behaviors->disable('Translate'). afterValidate. They are named in CamelCase and postfixed by Behavior. beforeDelete. } Creating Behaviors Behaviors that are attached to Models get their callbacks called automatically. array('className' => 'Tree')).see Callback Methods. Say that our familiar Category model needs to start behaving as a Christmas model. We may also need to find out if our behavior is handling those model callbacks. afterSave. } Just as we could completely detach a behavior from a model at runtime. } We can also use the load method to override behavior settings: // We will change one setting from our already attached behavior $this->Category->Behaviors->load('Tree'. The callbacks are similar to those found in Models: beforeFind. Release 2. Models . If we pass the name of a behavior to the method. we can also attach new behaviors. and if not we then restore its ability to react to them: // If our behavior is not handling model callbacks if (!$this->Category->Behaviors->enabled('Translate')) { // Tell it to start doing so $this->Category->Behaviors->enable('Translate'). afterDelete and onError . beforeSave. otherwise it will give us the list of attached behaviors: // If the Translate behavior is not attached if (!$this->Category->Behaviors->loaded('Translate')) { // Get the list of all behaviors the model has attached $behaviors = $this->Category->Behaviors->loaded().CakePHP Cookbook Documentation. Your behaviors should be placed in app/Model/Behavior. There’s also a method to obtain the list of behaviors a model has attached. ex. we can customize the alias it will be loaded as. it will tell us if that behavior is attached to the model. Find them in lib/Cake/Model/Behavior/. NameBehavior. array('left' => 'new_left_node')). beforeValidate. It’s often helpful to use a core behavior as a template when creating your own. but only on Christmas day: // If today is Dec 25 if (date('m/d') === '12/25') { // Our model needs to behave as a Christmas model $this->Category->Behaviors->load('Christmas'). 322 Chapter 6.php. afterFind. also allowing it to be loaded multiple times with different settings: // The behavior will be available as 'MyTree' $this->Category->Behaviors->load('MyTree'. And using aliasing.

All other supplied parameters are shifted one place to the right. $settings = array()) { if (!isset($this->settings[$Model->alias])) { $this->settings[$Model->alias] = array( 'option1_key' => 'option1_default_value'. $to) { // Do some flying. 'montreal'). } More on models 323 . When creating behavior methods you automatically get passed a reference of the calling model as the first parameter. Release 2. the method signature should look like: public function fly(Model $Model. ). you can add settings per behavior and/or model behavior attachment. When created behaviors will have their setup() method called: public function setup(Model $Model.x Every callback and behavior method takes a reference to the model it is being called from as the first parameter. } Creating behavior methods Behavior methods are automatically available on any model acting as the behavior. For example: $this->Duck->fly('toronto'. Although this method takes two parameters. } $this->settings[$Model->alias] = array_merge( $this->settings[$Model->alias]. $from. A quick example that illustrates how behavior settings can be passed from the model to the behavior: class Post extends AppModel { public $actsAs = array( 'YourBehavior' => array( 'option1_key' => 'option1_value' ) ). 'option3_key' => 'option3_default_value'. 'option2_key' => 'option2_default_value'. For example if you had: class Duck extends AppModel { public $actsAs = array('Flying').CakePHP Cookbook Documentation. Besides implementing the callbacks. it’s a good practice to store the settings per alias/model name that is using the behavior. } You would be able to call FlyingBehavior methods as if they were methods on your Duck model. } Since behaviors are shared across all the model instances that use them. Information about specifying settings can be found in the chapters about core behaviors and their configuration. (array)$settings).

but the called method name will be the 2nd parameter. This allows you to create methods similar to Model::findAllByXXX methods on your behaviors. If the above behavior was attached to a model the following would happen: $model->doReleaseTheHounds('karl'. // would output 'ReleaseTheHounds'. All behavior callbacks are fired before the model callbacks are: • beforeFind • afterFind • beforeValidate • afterValidate • beforeSave • afterSave • beforeDelete • afterDelete 324 Chapter 6. public function doSomething(Model $model. Release 2. $arg1. The method signature for a mapped method is slightly different than a normal behavior mixin method: class MyBehavior extends ModelBehavior { public $mapMethods = array('/do(\w+)/' => 'doSomething'). //do something } } The above will map every doXXX() method call to the behavior. Behavior callbacks allow your behaviors to capture events in attached models and augment the parameters or splice in additional behavior. 'karl'.CakePHP Cookbook Documentation. 'lenny' Behavior callbacks Model Behaviors can define a number of callbacks that are triggered before the model callbacks of the same name. behaviors can also provide pattern matching methods. Mapped methods need to be declared in your behaviors $mapMethods array. As you can see. Behaviors can also define mapped methods.x Keep in mind that methods called in a $this->doIt() fashion from inside a behavior method will not get the $model parameter automatically appended. $method. Models . $arg2) { debug(func_get_args()). much like Model::findAllByXX. Mapped methods In addition to providing ‘mixin’ methods. the model is still the first parameter. This allows you to munge the method name for additional information. 'lenny'). Mapped methods use pattern matching for method invocation.

a summary of which is listed here for your convenience: More on models 325 . The settings come from the attached model’s $actsAs property. array $options = array()) You can use beforeValidate to modify a model’s validate array or handle any other pre-validation logic. You can override this method and provide custom cleanup functionality. CakePHP is distributed with several database-specific datasources (see the class files in lib/Cake/Model/Datasource/Database). Return true to allow it continue. The base method removes model settings based on $model->alias. Release 2. Much like regular behavior methods. and false when a record is updated. ModelBehavior::beforeSave(Model $Model. ModelBehavior::cleanup(Model $Model) Called when a behavior is detached from a model. Returning false from a beforeValidate callback will abort the validation and cause it to fail. boolean $primary = false) You can use the afterFind to augment the results of a find. Returning an array will augment the query parameters used for the find operation. they receive a $Model parameter as the first argument. Return true to allow it continue. array $options = array()) You can use afterSave to perform clean up operations related to your behavior. The return value will be passed on as the results to either the next behavior in the chain or the model’s afterFind. boolean $created. ModelBehavior::beforeDelete(Model $Model. ModelBehavior::afterFind(Model $Model. ModelBehavior::afterValidate(Model $Model) You can use afterValidate to perform any data cleanup or preparation if needed. boolean $cascade = true) You can return false from a behavior’s beforeDelete to abort the delete. This parameter is the model that the behavior method was invoked on. array $query) If a behavior’s beforeFind return’s false it will abort the find(). ModelBehavior::afterDelete(Model $Model) You can use afterDelete to perform clean up operations related to your behavior. DataSources DataSources are the link between models and the source of data that models represent.CakePHP Cookbook Documentation. $created will be true when a record is created. ModelBehavior::afterSave(Model $Model. ModelBehavior::setup(Model $Model. PostgreSQL or Microsoft SQL Server. mixed $results. the data is retrieved from a relational database such as MySQL. array $options = array()) You can return false from a behavior’s beforeSave to abort the save. ModelBehavior::beforeFind(Model $Model. array $settings = array()) Called when a behavior is attached to a model. In many cases.x Creating a behavior callback class ModelBehavior Model behavior callbacks are defined as simple methods in your behavior class. ModelBehavior::beforeValidate(Model $Model.

0 326 Chapter 6. $values = null. or SQLite) is your best bet. read. Most people. $fields = null. $queryData = array(). which aggregates some logic that is common to most relational databases. you’ve been using them all along. Release 2. update. You need not implement more of the methods listed above than necessary . $recursive = null) – update(Model $model. $id = null) It is also possible (and sometimes quite useful) to define the $_schema class attribute inside the datasource itself. and delete. Models . $conditions = null) – delete(Model $model. update and/or delete (the actual method signatures & implementation details are not important for the moment. CakePHP transparently uses the corresponding database datasource for all model operations. All of the above sources derive from a base DboSource class. $fields = null. instead of in the model. such as remote REST APIs or even an LDAP server.com/cakephp/datasources/tree/2. $func. MySQL. If you decide to write a RDBMS datasource. are interested in writing datasources for external sources of data.php.g.CakePHP Cookbook Documentation. and will be described later). So that’s what we’re going to look at now. Methods that must be implemented for all CRUD methods: • describe($model) • listSources($data = null) • calculate($model. So.x • Mysql • Postgres • Sqlite • Sqlserver Note: You can find additional community contributed datasources in the CakePHP DataSources repository on GitHub3 . 3 https://github. however. Basic API For DataSources A datasource can. $params) • At least one of: – create(Model $model. When specifying a database connection configuration in app/Config/database. working from one of these (e.if you need a read-only datasource. $values = null) – read(Model $model. and should implement at least one of the following methods: create. there’s no reason to implement create. even though you might not have known about datasources.

). where you can decide to implement whichever features you need (e. /** * Our default config options. We’ll call it FarAwaySource and we’ll put it in app/Model/Datasource/FarAwaySource. ). 'null' => true. 'length' => 11.x And that’s pretty much all there is to it. These options will be customized in our * ``app/Config/database. By coupling this datasource to a model. An Example A common reason you would want to write your own datasource is when you would like to access a 3rd party API using the usual Model::find()/save()/delete() methods. ). Release 2. 'null' => false.CakePHP Cookbook Documentation. 'key' => 'primary'. and the appropriate data and/or parameters used to call those methods will be passed on to the datasource itself. ). */ public $config = array( 'apiKey' => ''. eg. you are then able to use Model::find()/save()/delete() as you would normally. */ protected $_schema = array( 'id' => array( 'type' => 'integer'. ). 'null' => true. 'Network/Http'). * fixtures and schema migrations. 'name' => array( 'type' => 'string'.g. Let’s write a datasource that will access a fictitious remote JSON based API. 'length' => 255. class FarAwaySource extends DataSource { /** * An optional description of your datasource */ public $description = 'A far away datasource'. 'message' => array( 'type' => 'text'.php`` and will be merged in the ``__construct()``.php: App::uses('HttpSocket'. More on models 327 . Model::find options such as ’conditions’ parsing. We use the same array keys as we do with CakeSchema. ’limit’ or even your own custom parameters). /** * If we want to create() or update() we need to specify the fields * available.

} /** * calculate() is for determining how we will count the records and is * required to get ``update()`` and ``delete()`` to work. Calls to ``Model::find()`` arrive here. */ public function read(Model $model. */ public function __construct($config) { parent::__construct($config). We could either check the remote source or some 328 Chapter 6. $queryData = array().x /** * Create our HttpSocket and handle any config tweaks. */ public function calculate(Model $model. The easiest way is to just * return the string 'COUNT' and check for it in ``read()`` where * ``$data['fields'] === 'COUNT'``. $this->Http = new HttpSocket(). */ public function listSources($data = null) { return null. Release 2.CakePHP Cookbook Documentation. If this is your case then set a ``schema`` property on your * models and simply return ``$model->schema`` here instead. */ public function describe($model) { return $this->_schema. } /** * describe() tells the model your schema for ``Model::save()``. $params = array()) { return 'COUNT'. $recursive = null) { /** * Here we do the actual count as instructed by our calculate() * method above. So just ``return null``. * * We don't count the records here but return a string to be passed to * ``read()`` which will do the actual counting. } /** * Since datasources normally connect to a database there are a few things * we must change to get them to work without a database. * * You may want a different schema for each model but still use a single * datasource. */ /** * listSources() is for caching. } /** * Implement the R in CRUD. $func. Models . You'll likely want to implement caching in * your own way with a custom datasource.

true). Calls to ``Model::delete()`` arrive here. decode and return the remote data. $data). array( More on models 329 . Depending on the remote source you can just call * ``$this->create()``. */ public function delete(Model $model. $data['apiKey'] = $this->config['apiKey']. $queryData['conditions'] ).json'.com/api/list. throw new CakeException($error). Calls to ``Model::save()`` with $Model->id * set arrive here.CakePHP Cookbook Documentation. */ if ($queryData['fields'] === 'COUNT') { return array(array(array('count' => 1))).x * other way to get the record count. $values = null) { $data = array_combine($fields. */ $queryData['conditions']['apiKey'] = $this->config['apiKey']. $fields = null. Here we'll simply return 1 so * ``update()`` and ``delete()`` will assume the record exists. $res = json_decode($json. */ public function update(Model $model. throw new CakeException($error). if (is_null($res)) { $error = json_last_error(). } return array($model->alias => $res). */ public function create(Model $model. Release 2. true). $values).json'. $json = $this->Http->get( 'http://example. Calls to ``Model::save()`` without $model->id * set arrive here.json'. $fields. $fields = null. } /** * Implement the D in CRUD. } /** * Implement the U in CRUD. $json = $this->Http->post('http://example. } /** * Implement the C in CRUD. $values).com/api/remove. $id = null) { $json = $this->Http->get('http://example. } return true. if (is_null($res)) { $error = json_last_error(). $res = json_decode($json. $conditions = null) { return $this->create($model. } /** * Now we get.com/api/set. $values = null.

Tip: Using find types other than ’all’ can have unexpected results if the result of your read method is not a numerically indexed array. )).id']. throw new CakeException($error). 'apiKey' => $this->config['apiKey']. And delete the message: 330 Chapter 6. 'apiKey' => '1234abcd'. true). } We can retrieve data from our remote source using the familiar model methods: // Get all messages from 'Some Person' $messages = $this->MyModel->find('all'. Update the previous message: $this->MyModel->id = 42. ). 'message' => 'New Message'.x 'id' => $id[$model->alias . Release 2. array( 'conditions' => array('name' => 'Some Person').php file by adding something like this: public $faraway = array( 'datasource' => 'FarAwaySource'. } return true. $this->MyModel->save(array( 'message' => 'Updated message'. '. Models . $res = json_decode($json. Then use the database config in our models like this: class MyModel extends AppModel { public $useDbConfig = 'faraway'. )). )). } } We can then configure the datasource in our app/Config/database. )). if (is_null($res)) { $error = json_last_error(). Similarly we can save a new message: $this->MyModel->save(array( 'name' => 'Some Person'.CakePHP Cookbook Documentation.

Mac OS X or FreeBSD. useDbConfig The useDbConfig property is a string that specifies the name of the database connection to use to bind your model class to the related database table. Simply place your datasource file into Plugin/[YourPlugin]/Model/Datasource/[YourSource].FarAwaySource'. The database configuration file is stored in /app/Config/database. Example usage: 4 http://api.php and refer to it using the plugin notation: public $faraway = array( 'datasource' => 'MyPlugin.org/2. Model Attributes Model attributes allow you to set properties that can override the default model behavior.cakephp. As the Native Client is available only for Windows you will not be able to install it on Linux. Plugin DataSources You can also package Datasources into plugins. Release 2. The useDbConfig property is defaulted to the ‘default’ database connection.8/class-Model. First check if the SQL Server PHP extension pdo_sqlsrv and the SQL Server Native Client are installed properly. or could not be created. So if the Sqlserver Datasource errors out with: Error: Database connection "Sqlserver" is missing. For a complete list of model attributes and their descriptions visit the CakePHP API4 . 'apiKey' => 'abcd1234'. You can set it to any of the database connections defined within your database configuration file.html More on models 331 .php. Also the SQL Server Native Client must be installed for the extension to work. Connecting to SQL Server The Sqlserver datasource depends on Microsoft’s PHP extension called pdo_sqlsrv.CakePHP Cookbook Documentation. ). This PHP Extension is not included in the base installation of PHP and must be installed separately.x $this->MyModel->delete(42).

or set it to false if you wish the model to use no database table. plural form of the model’s class name. Example usage: class Example extends AppModel { // example_id is the field name in the database public $primaryKey = 'example_id'. } 332 Chapter 6. Models . // This model does not use a database table } Alternatively: class Example extends AppModel { public $useTable = 'exmp'. The default is no prefix. Set this attribute to the name of an alternate table.php. You can override the default by setting the tablePrefix attribute in the model. By default. You may change which field name the model uses as its primary key.CakePHP Cookbook Documentation. // This model uses a database table 'exmp' } tablePrefix The name of the table prefix used for the model. The table prefix is initially set in the database connection file at /app/Config/database. Example usage: class Example extends AppModel { public $useTable = false. This is common when setting CakePHP to use an existing database table. // will look for 'alternate_examples' } primaryKey Each table normally has a primary key. id. } useTable The useTable property specifies the database table name. Example usage: class Example extends AppModel { public $tablePrefix = 'alternate_'. the model uses the lowercase.x class Example extends AppModel { public $useDbConfig = 'alternate'. Release 2.

Raise it only when needed or use Containable behavior. its associated Users. this could mean adding domain_id. For example. This avoids retrieving related data where that is unnecessary or even unwanted.CakePHP Cookbook Documentation. Also note that the default recursive level is 1.x displayField The displayField attribute specifies which database field should be used as a label for the record. The recommended recursive level for your application should be -1. using the value -1 for recursive will disable all event triggering in the associated model. This happens because no relations are created when the value is set to -1. its domain. For example. Imagine your application features Groups which belong to a domain and have many Users which in turn have many Articles. you will have to add the columns containing the required foreign keys to the fields array manually. } Multiple field names cannot be combined into a single display field. ’last_name’) as the display field. You can achieve that by adding it to the AppModel: public $recursive = -1. This is most likely the case for most of your find() calls. Release 2. Note: If you want to combine $recursive with the fields functionality. and the Users’ associated Articles Set it no higher than you need. to use the username field: class User extends AppModel { public $displayField = 'username'. The label is used in scaffolding and in find(’list’) calls. In the example above. If you use events in your system. array(’first_name’. Instead create a virtual field with the Model attribute virtualFields recursive The recursive property defines how deep CakePHP should go to fetch associated model data via find(). by default. you cannot specify. You can set $recursive to different values based on the amount of data you want back from a $this->Group->find() call: • -1 CakePHP fetches Group data only. no joins. • 0 CakePHP fetches Group data and its domain • 1 CakePHP fetches a Group. and read() methods. Having CakePHP fetch data you aren’t going to use slows your app unnecessarily. More on models 333 . its domain and its associated Users • 2 CakePHP fetches a Group. The model will use name or title.

you may need to access information stored in $data inside of model callbacks. In SQL Server. integer Maps to the INTEGER. "Model. NCHAR and NVARCHAR types are used.field DESC".field" => "asc". uuid Maps to the UUID type if a database provides one.field asc". MONEY types.field". Possible values include: $order $order $order $order $order $order = = = = = = "field" "Model. otherwise this will generate a CHAR(36) field. _schema Contains metadata describing the model’s database table fields. DOUBLE PRECISION types. "Model.field ASC". time Maps to a TIME type in all databases. While data returned from a model class is normally used as returned from a find() call. date Maps to a timezone naive DATE column type. data The container for the model’s fetched data. binary Maps to the BLOB or BYTEA type provided by the database. array("Model. In PostgreSQL. boolean Maps to BOOLEAN except in MySQL. float Maps to the REAL. • null 334 Chapter 6. SMALLINT types provided by the database.CakePHP Cookbook Documentation. datetime Maps to a timezone naive DATETIME column type. NUMERIC types. text Maps to TEXT. decimal Maps to the DECIMAL. "Model.x order The default ordering of data for any find operation. timestamp Maps to the TIMESTAMP type.field2" => "DESC"). and SQL Server this turns into a TIMESTAMP or TIMESTAMPTZ type. Each field is described by: • name • type The types CakePHP supports are: string Generally backed by CHAR or VARCHAR columns. Models . biginteger Maps to the BIGINT type provided by the database. where TINYINT(1) is used to represent booleans. Release 2. "Model.

your User results would contain a name key with the result of the concatenation.first_name. see the Data Validation later on in this manual. as well as limitations. It is not advisable to create virtual fields with the same names as columns on the database. 'length' => 30 ). More on models 335 . 'length' => 30 ). see Virtual fields. Example usage for MySQL: public $virtualFields = array( 'name' => "CONCAT(User.x • default value • length Example Usage: protected $_schema = array( 'first_name' => array( 'type' => 'string'. its proper usage. In subsequent find operations. 'email' => array( 'type' => 'string'.CakePHP Cookbook Documentation. 'length' => 30 ). Note: It is not necessary to call validate() before save() as save() will automatically validate your data before actually saving. ' '. validate This attribute holds rules that allow the model to make data validation decisions before saving. 'message' => array('type' => 'text') ). Fields added to this property will be read as other fields in a model but will not be saveable. Virtual fields are aliased SQL expressions.last_name)" ). User. Release 2. For more information on the virtualFields property. 'last_name' => array( 'type' => 'string'. virtualFields Array of virtual fields this model has. For more information on validation. Keys named after fields hold regex values allowing the model to try to make matches. this can cause SQL errors.

data fetched by the model during a single request is cached. This concept is often referred to as the fat model.interval 7 day)' . $recent = $this->Example->getRecent(). 'hasMany'.x name Name of the model. Release 2. This caching is in-memory only. ' and (curdate() . return $this->find('all'. If you do not specify it in your model file it will be set to the class name by constructor. Models .CakePHP Cookbook Documentation. Any duplicate requests for the same data is handled by the cache. } } This getRecent() method can now be used within the controller. array $query = array()) Builds the query array that is used by the data source to generate the query to fetch the data. Model::associations() Get associations: $result = $this->Example->associations(). don’t forget that model classes are just that: classes that allow you to write your own methods or define your own properties. Example usage: class Example extends AppModel { public $name = 'Example'. } cacheQueries If set to true. // $result equals array('belongsTo'.interval 0 day))' ). and only lasts for the duration of the request. Additional Methods and Properties While CakePHP’s model functions should get you where you need to go. 'hasAndBelongsToMany') Model::buildQuery(string $type = ’first’. 336 Chapter 6. Any operation that handles the saving and fetching of data is best housed in your model classes. compact('conditions')). 'hasOne'. class Example extends AppModel { public function getRecent() { $conditions = array( 'created BETWEEN (curdate() .

Model::getAffectedRows() Returns the number of rows affected by the last query. Model::getAssociated(string $type = null) Gets all the models with which this model is associated. More on models 337 . and then performs a Model::find(’count’) on the currently configured datasource to ascertain the existence of the record in persistent storage... Model::getColumnType(string $column) Returns the column type of a column in the model. Model::escapeField(string $field = null.1. Escaping is done according to the current database driver’s rules. Note: Parameter $id was added in 2. $this->Example->id = 9. Model::getColumnTypes() Returns an associative array of field names and column types. } $exists = $this->Foo->exists(2). Release 2. string $alias = null) Escapes the field name and prepends the model name.CakePHP Cookbook Documentation. mixed $data) Deconstructs a complex data type (array or object) into a single field value. If ID is not provided it calls Model::getID() to obtain the current record ID to verify. Prior to that it does not take any parameter. Model::exists($id) Returns true if a record with the particular ID exists.x Model::deconstruct(string $field. if ($this->Example->exists()) { // .

CakePHP Cookbook Documentation.last_name" ). They will be indexed under the model’s key alongside other model fields. Using virtual fields Creating virtual fields is straightforward and easy. " ". Model::getLastInsertID() Alias to getInsertID(). It is not always useful to have User. Creating virtual fields Creating virtual fields is easy.x Model::getID(integer $list = 0) Returns the current record’s ID.e. In this case it may be better to just use first_name || \’ \’ || last_name without the Model Name.first_name fully qualified. 338 Chapter 6. Release 2. but will be treated like other model fields for read operations. you have multiple relations to other tables) this would result in an error. User. In each model you can define a $virtualFields property that contains an array of field => expressions. this can cause SQL errors. An example of a virtual field definition using MySQL would be: public $virtualFields = array( 'name' => 'CONCAT(User. your User results would contain a name key with the result of the concatenation. Virtual fields Virtual fields allow you to create arbitrary SQL expressions and assign them as fields in a Model. And with PostgreSQL: public $virtualFields = array( 'name' => "User. interacting with virtual fields can be done through a few different methods. In subsequent find operations. These fields cannot be saved.first_name || \' \' || User. Models . Model::getInsertID() Returns the ID of the last record this model inserted.first_name. It is not advisable to create virtual fields with the same names as columns on the database.last_name)' ). If you do not follow the convention (i.

Release 2.CakePHP Cookbook Documentation. ) ). true). Model::find() and virtual fields As stated earlier Model::find() will treat virtual fields much like any other field in a model. 'last_name' => 'Story'. virtualFields will also be checked when checking if a model has a field. //more fields. as there is no concrete field called name $this->User->hasField('name'). The value of a virtual field will be placed under the model’s key in the resultset: $results = $this->User->find('first'). Model::isVirtualField() This method can be used to check if a field/column is a virtual field or a concrete field.x Model::hasField() Model::hasField() will return true if the model has a concrete field passed by the first parameter. //false Model::getVirtualField() This method can be used to access the SQL expression that comprises a virtual field. If no argument is supplied it will return all virtual fields in a Model: //returns 'CONCAT(User. ' '. //true $this->User->isVirtualField('first_name'). User.last_name)' $this->User->getVirtualField('name'). // Will return true as there is a virtual field called name $this->User->hasField('name'.first_name. Will return true if the column is virtual: $this->User->isVirtualField('name'). 'name' => 'Mark Story'. Using the example field above: // Will return false. // results contains the following array( 'User' => array( 'first_name' => 'Mark'. More on models 339 . By setting the second parameter of hasField() to true.

CakePHP Cookbook Documentation. $this->virtualFields['name'] = sprintf( 'CONCAT(%s. Virtual fields in SQL queries Using functions in direct SQL queries will prevent data from being returned in the same array as your model’s data." ). $this->alias. Release 2. " ".last_name)'. $ds = null) { parent::__construct($id. For example this: $this->Timelog->query( "SELECT project_id.x Pagination and virtual fields Since virtual fields behave much like regular fields when doing find’s. If you are using virtualFields in models that have more than one alias it is best to define the virtualFields in your model’s constructor: public function __construct($id = false. $table. Virtual fields and model aliases When you are using virtualFields and models with aliases that are not the same as their name. %s. you can run into problems as virtualFields do not update to reflect the bound alias.5 ) 340 Chapter 6. would return something like this: Array ( [0] => Array ( [Timelog] => Array ( [project_id] => 1234 ) [0] => Array ( [TotalHours] => 25. $ds). } This will allow your virtualFields to work for any alias you give a model.first_name. SUM(id) as TotalHours FROM timelogs AS Timelog GROUP BY project_id. Models . Controller::paginate() will be able to sort by virtual fields too. $this->alias ). $table = null.

order. Doing so will generally result in an SQL error as the fields are not replaced by the ORM. SUM(id) as Timelog__TotalHours FROM timelogs AS Timelog GROUP BY project_id. This is because it difficult to estimate the depth at which an associated model might be found. A common workaround for this implementation issue is to copy virtualFields from one model to another at runtime when you need to access them: $this->virtualFields['name'] = $this->Author->virtualFields['name']. We can add this new virtual field on the fly rather than permanently declaring it in the model. Release 2.x ) ) If we want to group TotalHours into our Timelog array we should specify a virtual field for our aggregate column. or fields arrays. We will provide a default value of 0 in case another query attempts to use this virtual field.CakePHP Cookbook Documentation. Running the query again after specifying the virtual field should result in a cleaner grouping of values: Array ( [0] => Array ( [Timelog] => Array ( [project_id] => 1234 [TotalHours] => 25." ). If that were to occur. First you cannot use virtualFields on associated models for conditions. or: More on models 341 . In addition to adding the virtual field we also need to alias our column using the form of MyModel__MyField like this: $this->Timelog->query( "SELECT project_id. 0 would be returned in the TotalHours column: $this->Timelog->virtualFields['TotalHours'] = 0.5 ) ) ) Limitations of virtualFields The implementation of virtualFields has a few limitations.

. } else { $dataSource->rollback(). The transaction will finish only when the number of commit and rollback calls match with begin. You can then use the data source to start. use: $dataSource = $this->getDataSource(). a model’s table must be of a datasource and type which supports transactions. // Perform some tasks $dataSource->begin(). Models . $dataSource->begin(). // More few tasks if (/*latest task ok*/) { $dataSource->commit(). disable it using $dataSource->useNestedTransactions = false. It will use only one global transaction.. } else { $dataSource->rollback(). The methods will always return true when in transaction mode and the nested is not supported or disabled. Transactions To perform a transaction. commit. $dataSource->begin(). 342 default. // Perform some tasks if (/*all's well*/) { $dataSource->commit(). All transaction methods must be performed on a model’s DataSource object.CakePHP Cookbook Documentation. Enable it using Chapter 6. } Nested Transactions It is possible to start a transaction several times using the Datasource::begin() method.x $this->virtualFields += $this->Author->virtualFields. If you want to use multiple begin’s but not use the nested transaction from database. // Change something in main task } $dataSource->commit(). To get a model’s DataSource from within the model. The real nested transaction is disabled by $dataSource->useNestedTransactions = true. Release 2. This will perform the real nested transaction if your database supports it and it is enabled in the datasource. or roll back transactions.

CHAPTER 7

Core Libraries

CakePHP comes with a plethora of built-in functions and classes. These classes and functions try to cover
some of the most common features required in web applications.

General Purpose
General purpose libraries are available and reused in many places across CakePHP.

General Purpose
Global Constants and Functions
While most of your day-to-day work in CakePHP will be utilizing core classes and methods, CakePHP
features a number of global convenience functions that may come in handy. Many of these functions are
for use with CakePHP classes (loading model or component classes), but many others make working with
arrays or strings a little easier.
We’ll also cover some of the constants available in CakePHP applications. Using these constants will help
make upgrades more smooth, but are also convenient ways to point to certain files or directories in your
CakePHP application.
Global Functions

Here are CakePHP’s globally available functions. Most of them are just convenience wrappers for other
CakePHP functionality, such as debugging and translating content.
__(string $string_id[, $formatArgs ])
This function handles localization in CakePHP applications. The $string_id identifies the ID for
a translation. Strings used for translations are treated as format strings for sprintf(). You can
supply additional arguments to replace placeholders in your string:

343

CakePHP Cookbook Documentation, Release 2.x

__('You have %s unread messages', h($number));

Note: Check out the Internationalization & Localization section for more information.
__c(string $msg, integer $category, mixed $args = null)
Note that the category must be specified with an I18n class constant, instead of only the constant
name. The values are:
•I18n::LC_ALL - LC_ALL
•I18n::LC_COLLATE - LC_COLLATE
•I18n::LC_CTYPE - LC_CTYPE
•I18n::LC_MONETARY - LC_MONETARY
•I18n::LC_NUMERIC - LC_NUMERIC
•I18n::LC_TIME - LC_TIME
•I18n::LC_MESSAGES - LC_MESSAGES
__d(string $domain, string $msg, mixed $args = null)
Allows you to override the current domain for a single message lookup.
Useful when internationalizing a plugin:
plugin’);

echo __d(’plugin_name’, ’This is my

__dc(string $domain, string $msg, integer $category, mixed $args = null)
Allows you to override the current domain for a single message lookup. It also allows you to specify
a category.
Note that the category must be specified with an I18n class constant, instead of only the constant
name. The values are:
•I18n::LC_ALL - LC_ALL
•I18n::LC_COLLATE - LC_COLLATE
•I18n::LC_CTYPE - LC_CTYPE
•I18n::LC_MONETARY - LC_MONETARY
•I18n::LC_NUMERIC - LC_NUMERIC
•I18n::LC_TIME - LC_TIME
•I18n::LC_MESSAGES - LC_MESSAGES
__dcn(string $domain, string $singular, string $plural, integer $count, integer $category, mixed
$args = null)
Allows you to override the current domain for a single plural message lookup. It also allows you to
specify a category. Returns correct plural form of message identified by $singular and $plural for
count $count from domain $domain.
Note that the category must be specified with an I18n class constant, instead of only the constant
name. The values are:
344

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

•I18n::LC_ALL - LC_ALL
•I18n::LC_COLLATE - LC_COLLATE
•I18n::LC_CTYPE - LC_CTYPE
•I18n::LC_MONETARY - LC_MONETARY
•I18n::LC_NUMERIC - LC_NUMERIC
•I18n::LC_TIME - LC_TIME
•I18n::LC_MESSAGES - LC_MESSAGES
__dn(string $domain, string $singular, string $plural, integer $count, mixed $args = null)
Allows you to override the current domain for a single plural message lookup. Returns correct plural
form of message identified by $singular and $plural for count $count from domain $domain.
__n(string $singular, string $plural, integer $count, mixed $args = null)
Returns correct plural form of message identified by $singular and $plural for count $count. Some
languages have more than one form for plural messages dependent on the count.
am(array $one, $two, $three...)
Merges all the arrays passed as parameters and returns the merged array.
config()
Can be used to load files from your application config-folder via include_once. Function checks
for existence before include and returns boolean. Takes an optional number of arguments.
Example: config(’some_file’, ’myconfig’);
convertSlash(string $string)
Converts forward slashes to underscores and removes the first and last underscores in a string. Returns
the converted string.
debug(mixed $var, boolean $showHtml = null, $showFrom = true)
If the application’s DEBUG level is non-zero, $var is printed out. If $showHTML is true or left as
null, the data is rendered to be browser-friendly. If $showFrom is not set to false, the debug output
will start with the line from which it was called. Also see Debugging
stackTrace(array $options = array())
If the application’s DEBUG level is non-zero, the stack trace is printed out.
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.
fileExistsInPath(string $file)
Checks to make sure that the supplied file is within the current PHP include_path. Returns a boolean
result.
h(string $text, boolean $double = true, string $charset = null)
Convenience wrapper for htmlspecialchars().
General Purpose

345

CakePHP Cookbook Documentation, Release 2.x

LogError(string $message)
Shortcut to Log::write().
pluginSplit(string $name, boolean $dotAppend = false, string $plugin = null)
Splits a dot syntax plugin name into its plugin and class name. If $name does not have a dot, then
index 0 will be null.
Commonly used like list($plugin, $name) = pluginSplit(’Users.User’);
pr(mixed $var)
Convenience wrapper for print_r(), with the addition of wrapping <pre> tags around the output.
sortByKey(array &$array, string $sortby,
SORT_NUMERIC)
Sorts given $array by key $sortby.

string $order = ‘asc’,

integer $type =

stripslashes_deep(array $value)
Recursively strips slashes from the supplied $value. Returns the modified array.
Core Definition Constants

Most of the following constants refer to paths in your application.
constant APP
Absolute path to your application directory, including a trailing slash.
constant APP_DIR
Equals app or the name of your application directory.
constant APPLIBS
Path to the application’s Lib directory.
constant CACHE
Path to the cache files directory. It can be shared between hosts in a multi-server setup.
constant CAKE
Path to the cake directory.
constant CAKE_CORE_INCLUDE_PATH
Path to the root lib directory.
constant CORE_PATH
Path to the root directory with ending directory slash.
constant CSS
Path to the public CSS directory.
Deprecated since version 2.4.
constant CSS_URL
Web path to the CSS files directory.
Deprecated since version 2.4: Use config value App.cssBaseUrl instead.
constant DS
Short for PHP’s DIRECTORY_SEPARATOR, which is / on Linux and \ on Windows.
346

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

constant FULL_BASE_URL
Full URL prefix. Such as https://example.com
Deprecated since version 2.4:
Router::fullbaseUrl() instead.

This

constant

is

deprecated,

you

should

use

constant IMAGES
Path to the public images directory.
Deprecated since version 2.4.
constant IMAGES_URL
Web path to the public images directory.
Deprecated since version 2.4: Use config value App.imageBaseUrl instead.
constant JS
Path to the public JavaScript directory.
Deprecated since version 2.4.
constant JS_URL
Web path to the js files directory.
Deprecated since version 2.4: Use config value App.jsBaseUrl instead.
constant LOGS
Path to the logs directory.
constant ROOT
Path to the root directory.
constant TESTS
Path to the tests directory.
constant TMP
Path to the temporary files directory.
constant VENDORS
Path to the vendors directory.
constant WEBROOT_DIR
Equals webroot or the name of your webroot directory.
constant WWW_ROOT
Full path to the webroot.
Timing Definition Constants

constant TIME_START
Unix timestamp in microseconds as a float from when the application started.
constant SECOND
Equals 1

General Purpose

347

CakePHP Cookbook Documentation, Release 2.x

constant MINUTE
Equals 60
constant HOUR
Equals 3600
constant DAY
Equals 86400
constant WEEK
Equals 604800
constant MONTH
Equals 2592000
constant YEAR
Equals 31536000
App Class
class App
The app class is responsible for path management, class location and class loading. Make sure you follow
the File and Class Name Conventions.
Packages

CakePHP is organized around the idea of packages, each class belongs to a package or folder
where other classes reside. You can configure each package location in your application using
App::build(’APackage/SubPackage’, $paths) to inform the framework where should each
class be loaded. Almost every class in the CakePHP framework can be swapped with your own compatible
implementation. If you wish to use your own class instead of the classes the framework provides, just add
the class to your libs folder emulating the directory location of where CakePHP expects to find it.
For instance if you’d like to use your own HttpSocket class, put it under:
app/Lib/Network/Http/HttpSocket.php

Once you’ve done this App will load your override file instead of the file inside CakePHP.
Loading classes

static App::uses(string $class, string $package)
Return type void
Classes are lazily loaded in CakePHP, however before the autoloader can find your classes you need
to tell App, where it can find the files. By telling App which package a class can be found in, it can
properly locate the file and load it the first time a class is used.
Some examples for common types of classes are:
348

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

Console Commands App::uses(’AppShell’, ’Console/Command’);
Console Tasks App::uses(’BakeTask’, ’Console/Command/Task’);
Controllers App::uses(’PostsController’, ’Controller’);
Components App::uses(’AuthComponent’, ’Controller/Component’);
Models App::uses(’MyModel’, ’Model’);
Behaviors App::uses(’TreeBehavior’, ’Model/Behavior’);
Views App::uses(’ThemeView’, ’View’);
Helpers App::uses(’HtmlHelper’, ’View/Helper’);
Libs App::uses(’PaymentProcessor’, ’Lib’);
Vendors App::uses(’Textile’, ’Vendor’);
Utilities App::uses(’CakeText’, ’Utility’);
So basically the second param should simply match the folder path of the class file in core or app.
Note: Loading vendors usually means you are loading packages that do not follow conventions. For most
vendor packages using App::import() is recommended.

Loading files from plugins Loading classes in plugins works much the same as loading app and core
classes except you must specify the plugin you are loading from:
// Load the class Comment in app/Plugin/PluginName/Model/Comment.php
App::uses('Comment', 'PluginName.Model');
// Load the class CommentComponent in
// app/Plugin/PluginName/Controller/Component/CommentComponent.php
App::uses('CommentComponent', 'PluginName.Controller/Component');

Finding paths to packages using App::path()

static App::path(string $package, string $plugin = null)
Return type array
Used to read information stored path:
// return the model paths in your application
App::path('Model');

This can be done for all packages that are apart of your application. You can also fetch paths for a
plugin:
// return the component paths in DebugKit
App::path('Component', 'DebugKit');

General Purpose

349

CakePHP Cookbook Documentation, Release 2.x

static App::paths()
Return type array
Get all the currently loaded paths from App. Useful for inspecting or storing all paths App knows
about. For a paths to a specific package use App::path()
static App::core(string $package)
Return type array
Used for finding the path to a package inside CakePHP:
// Get the path to Cache engines.
App::core('Cache/Engine');

static App::location(string $className)
Return type string
Returns the package name where a class was defined to be located at.
Adding paths for App to find packages in

static App::build(array $paths = array(), mixed $mode = App::PREPEND)
Return type void
Sets up each package location on the file system. You can configure multiple search paths for each
package, those will be used to look for files one folder at a time in the specified order. All paths must
be terminated with a directory separator.
Adding additional controller paths for example would alter where CakePHP looks for controllers.
This allows you to split your application up across the filesystem.
Usage:
//will setup a new search path for the Model package
App::build(array('Model' => array('/a/full/path/to/models/')));
//will setup the path as the only valid path for searching models
App::build(array('Model' => array('/path/to/models/')), App::RESET);
//will setup multiple search paths for helpers
App::build(array(
'View/Helper' => array('/path/to/helpers/', '/another/path/')
));

If reset is set to true, all loaded plugins will be forgotten and they will be needed to be loaded again.
Examples:
App::build(array('controllers' => array('/full/path/to/controllers/')));
//becomes
App::build(array('Controller' => array('/full/path/to/Controller/')));

350

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

App::build(array('helpers' => array('/full/path/to/views/helpers/')));
//becomes
App::build(array('View/Helper' => array('/full/path/to/View/Helper/')));

Changed in version 2.0: App::build() will not merge app paths with core paths anymore.
Add new packages to an application App::build() can be used to add new package locations. This
is useful when you want to add new top level packages or, sub-packages to your application:
App::build(array(
'Service' => array('%s' . 'Service' . DS)
), App::REGISTER);

The %s in newly registered packages will be replaced with the APP path. You must include a trailing / in
registered packages. Once packages are registered, you can use App::build() to append/prepend/reset
paths like any other package.
Changed in version 2.1: Registering packages was added in 2.1
Finding which objects CakePHP knows about

static App::objects(string $type, mixed $path = null, boolean $cache = true)
Return type mixed Returns an array of objects of the given type or false if incorrect.
You can find out which objects App knows about using App::objects(’Controller’) for
example to find which application controllers App knows about.
Example usage:
//returns array('DebugKit', 'Blog', 'User');
App::objects('plugin');
//returns array('PagesController', 'BlogController');
App::objects('Controller');

You can also search only within a plugin’s objects by using the plugin dot syntax.
// returns array('MyPluginPost', 'MyPluginComment');
App::objects('MyPlugin.Model');

Changed in version 2.0.
1.Returns array() instead of false for empty results or invalid types
2.Does not return core objects anymore, App::objects(’core’) will return array().
3.Returns the complete class name
Locating plugins

static App::pluginPath(string $plugin)
General Purpose

351

CakePHP Cookbook Documentation, Release 2.x

Return type string
Plugins can be located with App as well. Using App::pluginPath(’DebugKit’); for example, will give you the full path to the DebugKit plugin:
$path = App::pluginPath('DebugKit');

Locating themes

static App::themePath(string $theme)
Return type string
Themes can be found App::themePath(’purple’);, would give the full path to the purple
theme.
Including files with App::import()

static App::import(mixed $type = null, string $name = null, mixed $parent = true, array $search
= array(), string $file = null, boolean $return = false)
Return type boolean
At first glance App::import seems complex, however in most use cases only 2 arguments are
required.
Note: This method is equivalent to require‘ing the file. It is important to realize that the class
subsequently needs to be initialized.
// The same as require('Controller/UsersController.php');
App::import('Controller', 'Users');
// We need to load the class
$Users = new UsersController();
// If we want the model associations, components, etc to be loaded
$Users->constructClasses();

All classes that were loaded in the past using App::import(‘Core’, $class) will need to be loaded
using App::uses() referring to the correct package. This change has provided large performance
gains to the framework.
Changed in version 2.0.
•The method no longer looks for classes recursively, it strictly uses the values for the paths defined
in App::build()
•It will not be able to load App::import(’Component’, ’Component’) use
App::uses(’Component’, ’Controller’);.
•Using App::import(’Lib’, ’CoreClass’); to load core classes is no longer possible.

352

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

•Importing a non-existent file, supplying a wrong type or package name, or null values for $name
and $file parameters will result in a false return value.
•App::import(’Core’, ’CoreClass’) is no longer supported, use App::uses() instead and let the class autoloading do the rest.
•Loading Vendor files does not look recursively in the vendors folder, it will also not convert the
file to underscored anymore as it did in the past.
Overriding classes in CakePHP

You can override almost every class in the framework, exceptions are the App and Configure classes.
Whenever you like to perform such overriding, just add your class to your app/Lib folder mimicking the
internal structure of the framework. Some examples to follow:
• To override the Dispatcher class, create app/Lib/Routing/Dispatcher.php
• To override the CakeRoute class, create app/Lib/Routing/Route/CakeRoute.php
• To override the Model class, create app/Lib/Model/Model.php
When you load the overridden classes now, the files in app/Lib will be loaded instead of the built-in core
ones.
Loading Vendor Files

You can use App::uses() to load classes in vendors directories. It follows the same conventions as
loading other files:
// Load the class Geshi in app/Vendor/Geshi.php
App::uses('Geshi', 'Vendor');

To load classes in subdirectories, you’ll need to add those paths with App::build():
// Load the class ClassInSomePackage in
// app/Vendor/SomePackage/ClassInSomePackage.php
App::build(array('Vendor' => array(APP . 'Vendor' . DS . 'SomePackage' . DS)));
App::uses('ClassInSomePackage', 'Vendor');

Your vendor files may not follow conventions, have a class that differs from the file name or does not contain
classes. You can load those files using App::import(). The following examples illustrate how to load
vendor files from a number of path structures. These vendor files could be located in any of the vendor
folders.
To load app/Vendor/geshi.php:
App::import('Vendor', 'geshi');

Note: The geshi file must be a lower-case file name as CakePHP will not find it otherwise.
To load app/Vendor/flickr/flickr.php:

General Purpose

353

CakePHP Cookbook Documentation, Release 2.x

App::import('Vendor', 'flickr', array('file' => 'flickr/flickr.php'));

To load app/Vendor/some.name.php:
App::import('Vendor', 'SomeName', array('file' => 'some.name.php'));

To load app/Vendor/services/well.named.php:
App::import(
'Vendor',
'WellNamed',
array('file' => 'services' . DS . 'well.named.php')
);

To load app/Plugin/Awesome/Vendor/services/well.named.php:
App::import(
'Vendor',
'Awesome.WellNamed',
array('file' => 'services' . DS . 'well.named.php')
);

To load app/Plugin/Awesome/Vendor/Folder/Foo.php:
App::import(
'Vendor',
'Awesome.Foo',
array('file' => 'Folder' . DS . 'Foo.php'));

It wouldn’t make a difference if your vendor files are inside your /vendors directory. CakePHP will automatically find it.
To load vendors/vendorName/libFile.php:
App::import(
'Vendor',
'aUniqueIdentifier',
array('file' => 'vendorName' . DS . 'libFile.php')
);

App Init/Load/Shutdown Methods

static App::init()
Return type void
Initializes the cache for App, registers a shutdown function.
static App::load(string $className)
Return type boolean
Method to handle the automatic class loading. It will look for each class’ package defined using
App::uses() and with this information it will resolve the package name to a full path to load the

354

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

class from. File name for each class should follow the class name. For instance, if a class is name
MyCustomClass the file name should be MyCustomClass.php
static App::shutdown()
Return type void
Object destructor. Writes cache file if changes have been made to the $_map.
Events System
New in version 2.1.
Creating maintainable applications is both a science and an art. It is well-known that a key for having good
quality code is making your objects loosely coupled and strongly cohesive at the same time. Cohesion
means that all methods and properties for a class are strongly related to the class itself and it is not trying
to do the job other objects should be doing, while loosely coupling is the measure of how little a class is
“wired” to external objects, and how much that class is depending on them.
There are certain cases where you need to cleanly communicate with other parts of an application, without
having to hard code dependencies, thus losing cohesion and increasing class coupling. Using the Observer
pattern, which allows objects to notify other objects and anonymous listeners about changes is a useful
pattern to achieve this goal.
Listeners in the observer pattern can subscribe to events and choose to act upon them if they are relevant. If
you have used JavaScript, there is a good chance that you are already familiar with event driven programming.
CakePHP emulates several aspects of how events are triggered and managed in popular JavaScript libraries
such as jQuery. In the CakePHP implementation, an event object is dispatched to all listeners. The event
object holds information about the event, and provides the ability to stop event propagation at any point.
Listeners can register themselves or can delegate this task to other objects and have the chance to alter the
state and the event itself for the rest of the callbacks.
The event subsystem is at the heart of Model, Behavior, Controller, View and Helper callbacks. If you’ve
ever used any of them, you are already somewhat familiar with events in CakePHP.
Example Event Usage

Let’s suppose you are building a Cart plugin, and you’d like to focus on just handling order logic. You don’t
really want to include shipping logic, emailing the user or decrementing the item from the stock, but these
are important tasks to the people using your plugin. If you were not using events, you may try to implement
this by attaching behaviors to models, or adding components to your controllers. Doing so represents a
challenge most of the time, since you would have to come up with the code for externally loading those
behaviors or attaching hooks to your plugin controllers.
Instead, you can use events to allow you to cleanly separate the concerns of your code and allow additional
concerns to hook into your plugin using events. For example in your Cart plugin you have an Order model
that deals with creating orders. You’d like to notify the rest of the application that an order has been created.
To keep your Order model clean you could use events:

General Purpose

355

CakePHP Cookbook Documentation, Release 2.x

// Cart/Model/Order.php
App::uses('CakeEvent', 'Event');
class Order extends AppModel {
public function place($order) {
if ($this->save($order)) {
$this->Cart->remove($order);
$event = new CakeEvent('Model.Order.afterPlace', $this, array(
'order' => $order
));
$this->getEventManager()->dispatch($event);
return true;
}
return false;
}
}

The above code allows you to easily notify the other parts of the application that an order has been created.
You can then do tasks like send email notifications, update stock, log relevant statistics and other tasks in
separate objects that focus on those concerns.
Accessing Event Managers

In CakePHP events are triggered against event managers. Event managers are available in every Model,
View and Controller using getEventManager():
$events = $this->getEventManager();

Each model has a separate event manager, while the View and Controller share one. This allows model
events to be self contained, and allow components or controllers to act upon events created in the view if
necessary.
Global Event Manager In addition to instance level event managers, CakePHP provides a global event
manager that allows you to listen to any event fired in an application. This is useful when attaching listeners
to a specific instance might be cumbersome or difficult. The global manager is a singleton instance of
CakeEventManager. When an event is dispatched, it will be dispatched to the both the global and
instance level listeners in priority order. You can access the global manager using a static method:
// In any configuration file or piece of code that executes before the event
App::uses('CakeEventManager', 'Event');
CakeEventManager::instance()->attach(
$aCallback,
'Model.Order.afterPlace'
);

One important thing you should consider is that there are events that will be triggered having the same name
but different subjects, so checking it in the event object is usually required in any function that gets attached
globally in order to prevent some bugs. Remember that with the flexibility of using the global manager,
some additional complexity is incurred.

356

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

Changed in version 2.5: Prior to 2.5, listeners on the global manager were kept in a separate list and fired
before instance listeners are. After 2.5, global and instance listeners are fired in priority order.
Dispatching Events

Once you have obtained an instance of an event manager you can dispatch events using dispatch(). This
method takes an instance of the CakeEvent class. Let’s look at dispatching an event:
// Create a new event and dispatch it.
$event = new CakeEvent('Model.Order.afterPlace', $this, array(
'order' => $order
));
$this->getEventManager()->dispatch($event);

CakeEvent accepts 3 arguments in its constructor. The first one is the event name, you should try
to keep this name as unique as possible, while making it readable. We suggest a convention as follows: Layer.eventName for general events happening at a layer level (e.g. Controller.startup,
View.beforeRender) and Layer.Class.eventName for events happening in specific classes on a
layer, for example Model.User.afterRegister or Controller.Courses.invalidAccess.
The second argument is the subject, meaning the object associated to the event, usually when it is
the same class triggering events about itself, using $this will be the most common case. Although a
Component could trigger controller events too. The subject class is important because listeners will get
immediate access to the object properties and have the chance to inspect or change them on the fly.
Finally, the third argument is any additional event data.This can be any data you consider useful to pass
around so listeners can act upon it. While this can be an argument of any type, we recommend passing an
associative array.
The dispatch() method accepts an event object as an argument and notifies all subscribed listeners.
Registering Listeners

Listeners are the preferred way to register callbacks for an event. This is done by implementing the
CakeEventListener interface in any class you wish to register some callbacks. Classes implementing it need to provide the implementedEvents() method. This method must return an associative
array with all event names that the class will handle.
To continue our previous example, let’s imagine we have a UserStatistic class responsible for calculating
a user’s purchasing history, and compiling into global site statistics. This is a great place to use a listener
class. Doing so allows you concentrate the statistics logic in one place and react to events as necessary. Our
UserStatistics listener might start out like:
// In app/Lib/Event/UserStatistic.php
App::uses('CakeEventListener', 'Event');
class UserStatistic implements CakeEventListener {
public function implementedEvents() {
return array(

General Purpose

357

CakePHP Cookbook Documentation, Release 2.x

'Model.Order.afterPlace' => 'updateBuyStatistic',
);
}
public function updateBuyStatistic($event) {
// Code to update statistics
}
}
// In a controller or somewhere else where $this->Order is accessible
// Attach the UserStatistic object to the Order's event manager
$statistics = new UserStatistic();
$this->Order->getEventManager()->attach($statistics);

As you can see in the above code, the attach function will accept instances of the
CakeEventListener interface. Internally, the event manager will use implementedEvents to attach the correct callbacks.
Registering Global Listeners As shown in the example above, event listeners are conventionally placed
in app/Lib/Event. Following this convention allows you to easily locate your listener classes. It is also
recommended that you attach global listeners during your application bootstrap process:
// In app/Config/bootstrap.php
// Load the global event listeners.
require_once APP . 'Config' . DS . 'events.php'

An example events bootstrap file for our cart application could look like:
// In app/Config/events.php
// Load event listeners
App::uses('UserStatistic', 'Lib/Event');
App::uses('ProductStatistic', 'Lib/Event');
App::uses('CakeEventManager', 'Event');
// Attach listeners.
CakeEventManager::instance()->attach(new UserStatistic());
CakeEventManager::instance()->attach(new ProductStatistic());

Registering Anonymous Listeners While event listener objects are generally a better way to implement
listeners, you can also bind any callable as an event listener. For example if we wanted to put any orders
into the log files, we could use a simple anonymous function to do so:
// Anonymous functions require PHP 5.3+
$this->Order->getEventManager()->attach(function($event) {
CakeLog::write(
'info',
'A new order was placed with id: ' . $event->subject()->id
);
}, 'Model.Order.afterPlace');

358

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

In addition to anonymous functions you can use any other callable type that PHP supports:
$events = array(
'email-sending' => 'EmailSender::sendBuyEmail',
'inventory' => array($this->InventoryManager, 'decrement'),
);
foreach ($events as $callable) {
$eventManager->attach($callable, 'Model.Order.afterPlace');
}

Establishing Priorities In some cases you might want to control the order that listeners are invoked. For
instance, if we go back to our user statistics example. It would ideal if this listener was called at the end of
the stack. By calling it at the end of the listener stack, we can ensure that the event was not canceled, and
that no other listeners raised exceptions. We can also get the final state of the objects in the case that other
listeners have modified the subject or event object.
Priorities are defined as an integer when adding a listener. The higher the number, the later the method will
be fired. The default priority for all listeners is 10. If you need your method to be run earlier, using any
value below this default will work. On the other hand if you desire to run the callback after the others, using
a number above 10 will do.
If two callbacks happen to have the same priority value, they will be executed with a the order they
were attached. You set priorities using the attach method for callbacks, and declaring it in the
implementedEvents function for event listeners:
// Setting priority for a callback
$callback = array($this, 'doSomething');
$this->getEventManager()->attach(
$callback,
'Model.Order.afterPlace',
array('priority' => 2)
);
// Setting priority for a listener
class UserStatistic implements CakeEventListener {
public function implementedEvents() {
return array(
'Model.Order.afterPlace' => array(
'callable' => 'updateBuyStatistic',
'priority' => 100
),
);
}
}

As you see, the main difference for CakeEventListener objects is that you need to use an array for
specifying the callable method and the priority preference. The callable key is an special array entry
that the manager will read to know what function in the class it should be calling.
Getting Event Data as Function Parameters By default listeners receive the event object as their only
parameter. If you are building an event that doesn’t need access to the event object you may want to have
General Purpose

359

CakePHP Cookbook Documentation, Release 2.x

the event data passed as function parameters. This feature is used by the callbacks CakePHP fires in order
to preserve backwards compatibility.
If you want to enable this feature, you have to add the passParams option to the third argument of the
attach method, or declare it in the implementedEvents returned array similar to what you do with
priorities:
// Enabling passed parameters mode for an anonymous listener
$callback = array($this, 'doSomething');
$this->getEventManager()->attach(
$callback,
'Model.Order.afterPlace',
array('passParams' => true)
);
// Enabling passed parameters mode for a listener
class UserStatistic implements CakeEventListener {
public function implementedEvents() {
return array(
'Model.Order.afterPlace' => array(
'callable' => 'updateBuyStatistic',
'passParams' => true
),
);
}
public function updateBuyStatistic($orderData) {
// ...
}
}

In the above code the doSomething function and updateBuyStatistic method will receive
$orderData instead of the $event object. This is so, because in our previous example we trigger
the Model.Order.afterPlace event with some data:
$event = new CakeEvent('Model.Order.afterPlace', $this, array(
'order' => $order
));
$this->getEventManager()->dispatch($event);

Note: The params can only be passed as function arguments if the event data is an array. Any other data
type cannot be converted to function parameters, thus not using this option is often the most adequate choice.

Stopping Events Much like DOM events, you may want to stop an event to prevent additional listeners
from being notified. You can see this in action during model callbacks (e.g. beforeSave) in which it is
possible to stop the saving operation if the code detects it cannot proceed any further.
In order to stop events you can either return false in your callbacks or call the stopPropagation
method on the event object:

360

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

public function doSomething($event) {
// ...
return false; // stops the event
}
public function updateBuyStatistic($event) {
// ...
$event->stopPropagation();
}

Stopping an event will prevent any additional callbacks from being called. Additionally the code triggering
the event may behave differently based on the event being stopped or not. Generally it does not make
sense to stop ‘after’ events, but stopping ‘before’ events is often used to prevent the entire operation from
occurring.
To check if an event was stopped, you call the isStopped() method in the event object:
public function place($order) {
$event = new CakeEvent(
'Model.Order.beforePlace',
$this, array('order' => $order)
);
$this->getEventManager()->dispatch($event);
if ($event->isStopped()) {
return false;
}
if ($this->Order->save($order)) {
// ...
}
// ...
}

In the previous example the order would not get saved if the event is stopped during the beforePlace
process.
Getting Event Results Every time a callback returns a value, it gets stored in the $result property of
the event object. This is useful when you want to allow callbacks to modify the event execution. Let’s take
again our beforePlace example and let callbacks modify the $order data.
Event results can be altered either using the event object result property directly or returning the value in the
callback itself:
// A listener callback
public function doSomething($event) {
// ...
$alteredData = $event->data['order'] + $moreData;
return $alteredData;
}
// Another listener callback
public function doSomethingElse($event) {
// ...

General Purpose

361

CakePHP Cookbook Documentation, Release 2.x

$event->result['order'] = $alteredData;
}
// Using the event result
public function place($order) {
$event = new CakeEvent(
'Model.Order.beforePlace',
$this, array('order' => $order)
);
$this->getEventManager()->dispatch($event);
if (!empty($event->result['order'])) {
$order = $event->result['order'];
}
if ($this->Order->save($order)) {
// ...
}
// ...
}

It is possible to alter any event object property and have the new data passed to the next callback. In most of
the cases, providing objects as event data or result and directly altering the object is the best solution as the
reference is kept the same and modifications are shared across all callback calls.
Removing Callbacks and Listeners If for any reason you want to remove any callback from the event
manager just call the CakeEventManager::detach() method using as arguments the first two params
you used for attaching it:
// Attaching a function
$this->getEventManager()->attach(array($this, 'doSomething'), 'My.event');
// Detaching the function
$this->getEventManager()->detach(array($this, 'doSomething'), 'My.event');
// Attaching an anonymous function (PHP 5.3+ only);
$myFunction = function($event) { ... };
$this->getEventManager()->attach($myFunction, 'My.event');
// Detaching the anonymous function
$this->getEventManager()->detach($myFunction, 'My.event');
// Attaching a CakeEventListener
$listener = new MyEventListener();
$this->getEventManager()->attach($listener);
// Detaching a single event key from a listener
$this->getEventManager()->detach($listener, 'My.event');
// Detaching all callbacks implemented by a listener
$this->getEventManager()->detach($listener);

362

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

Conclusion

Events are a great way of separating concerns in your application and make classes both cohesive and decoupled from each other. Events can be utilized to de-couple application code and make extensible plugins.
Keep in mind that with great power comes great responsibility. Using too many events can make debugging
harder and require additional integration testing.
Additional Reading

Collections Components, Helpers, Behaviors and Tasks all share a similar structure and set of behaviors.
For 2.0, they were given a unified API for interacting with collections of similar objects. The collection
objects in CakePHP, give you a uniform way to interact with several different kinds of objects in your
application.
While the examples below, will use Components, the same behavior can be expected for Helpers, Behaviors,
and Tasks in addition to Components.
Loading and unloading objects Loading objects on every kind of collection can be done using the
load() method:
$this->Prg = $this->Components->load('Prg');
$this->Prg->process();

When loading a component, if the component is not currently loaded into the collection, a new instance
will be created. If the component is already loaded, another instance will not be created. When loading
components, you can also provide additional configuration for them:
$this->Cookie = $this->Components->load('Cookie', array('name' => 'sweet'));

Any keys & values provided will be passed to the Component’s constructor. The one exception to this rule
is className. ClassName is a special key that is used to alias objects in a collection. This allows you
to have component names that do not reflect the classnames, which can be helpful when extending core
components:
$this->Auth = $this->Components->load(
'Auth',
array('className' => 'MyCustomAuth')
);
$this->Auth->user(); // Actually using MyCustomAuth::user();

The inverse of loading an object, is unloading it. Unloaded objects are removed from memory, and will not
have additional callbacks triggered on them:
$this->Components->unload('Cookie');
$this->Cookie->read(); // Fatal error.

General Purpose

363

CakePHP Cookbook Documentation, Release 2.x

Triggering callbacks Callbacks are supported by collection objects. When a collection has a callback
triggered, that method will be called on all enabled objects in the collection. You can pass parameters to the
callback loop as well:
$this->Behaviors->trigger('afterFind', array($this, $results, $primary));

In the above $this would be passed as the first argument to every behavior’s afterFind method. There are
several options that can be used to control how callbacks are fired:
• breakOn Set to the value or values you want the callback propagation to stop on. Can either be a
scalar value, or an array of values to break on. Defaults to false.
• break Set to true to enabled breaking. When a trigger is broken, the last returned value will be returned. If used in combination with collectReturn the collected results will be returned. Defaults
to false.
• collectReturn Set to true to collect the return of each object into an array. This array of return
values will be returned from the trigger() call. Defaults to false.
• triggerDisabled Will trigger the callback on all objects in the collection even the non-enabled
objects. Defaults to false.
• modParams Allows each object the callback gets called on to modify the parameters to the next
object. Setting modParams to an integer value will allow you to modify the parameter with that index.
Any non-null value will modify the parameter index indicated. Defaults to false.
Canceling a callback loop Using the break and breakOn options you can cancel a callback loop
midway similar to stopping event propagation in JavaScript:
$this->Behaviors->trigger(
'beforeFind',
array($this, $query),
array('break' => true, 'breakOn' => false)
);

In the above example, if any behavior returns false from its beforeFind method, no further callbacks will
be called. In addition, the return of trigger() will be false.
Enabling and disabling objects Once an object is loaded into a collection you may need to disable it.
Disabling an object in a collection prevents future callbacks from being fired on that object unless the
triggerDisabled option is used:
// Disable the HtmlHelper
$this->Helpers->disable('Html');
// Re-enable the helper later on
$this->Helpers->enable('Html');

Disabled objects can still have their normal methods and properties used. The primary difference between an
enabled and disabled object is with regards to callbacks. You can interrogate a collection about the enabled
objects, or check if a specific object is still enabled using enabled():

364

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

// Check whether or not a specific helper is enabled.
$this->Helpers->enabled('Html');
// $enabled will contain an array of helper currently enabled.
$enabled = $this->Helpers->enabled();

Object callback priorities You can prioritize the triggering object callbacks similar to event callbacks.
The handling of priority values and order of triggering is the same as explained here. Here’s how you can
specify priority at declaration time:
class SomeController {
public $components = array(
'Foo', //Foo gets default priority 10
// Bar's callbacks are triggered before Foo's
'Bar' => array('priority' => 9)
);
public $helpers = array(
// Cache's callbacks will be triggered last
'Cache' => array('priority' => 12),
'Asset',
'Utility' //Utility has priority 10 same as Asset and its callbacks
//are triggered after Asset's
);
}

class Post {
public $actsAs = array(
'DoFirst' => array('priority' => 1),
'Media'
);
}

When dynamically loading objects to a collection you can specify the priority like this:
$this->MyComponent = $this->Components->load(
'MyComponent',
array('priority' => 9)
);

You can also change priorities at run time using the ObjectCollection::setPriority() function:
//For a single object
$this->Components->setPriority('Foo', 2);
//For multiple objects
$this->Behaviors->setPriority(array('Object1' => 8, 'Object2' => 9));

Behaviors Model behaviors are a way to organize some of the functionality defined in CakePHP models.
They allow us to separate and reuse logic that creates a type of behavior, and they do this without requiring
General Purpose

365

CakePHP Cookbook Documentation, Release 2.x

inheritance. For example creating tree structures. By providing a simple yet powerful way to enhance
models, behaviors allow us to attach functionality to models by defining a simple class variable. That’s how
behaviors allow models to get rid of all the extra weight that might not be part of the business contract they
are modeling, or that is also needed in different models and can then be extrapolated.
As an example, consider a model that gives us access to a database table which stores structural information
about a tree. Removing, adding, and migrating nodes in the tree is not as simple as deleting, inserting, and
editing rows in the table. Many records may need to be updated as things move around. Rather than creating
those tree-manipulation methods on a per model basis (for every model that needs that functionality), we
could simply tell our model to use the TreeBehavior, or in more formal terms, we tell our model to
behave as a Tree. This is known as attaching a behavior to a model. With just one line of code, our
CakePHP model takes on a whole new set of methods that allow it to interact with the underlying structure.
CakePHP already includes behaviors for tree structures, translated content, access control list interaction, not to mention the community-contributed behaviors already available in the CakePHP Bakery
(http://bakery.cakephp.org). In this section, we’ll cover the basic usage pattern for adding behaviors to
models, how to use CakePHP’s built-in behaviors, and how to create our own.
In essence, Behaviors are Mixins1 with callbacks.
There are a number of Behaviors included in CakePHP. To find out more about each one, reference the
chapters below:
ACL
class AclBehavior
The Acl behavior provides a way to seamlessly integrate a model with your ACL system. It can create both
AROs or ACOs transparently.
To use the new behavior, you can add it to the $actsAs property of your model. When adding it to the actsAs
array you choose to make the related Acl entry an ARO or an ACO. The default is to create ACOs:
class User extends AppModel {
public $actsAs = array('Acl' => array('type' => 'requester'));
}

This would attach the Acl behavior in ARO mode. To join the ACL behavior in ACO mode use:
class Post extends AppModel {
public $actsAs = array('Acl' => array('type' => 'controlled'));
}

For User and Group models it is common to have both ACO and ARO nodes, to achieve this use:
class User extends AppModel {
public $actsAs = array('Acl' => array('type' => 'both'));
}

You can also attach the behavior on the fly like so:
$this->Post->Behaviors->load('Acl', array('type' => 'controlled'));
1

http://en.wikipedia.org/wiki/Mixin

366

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

Changed in version 2.1: You can now safely attach AclBehavior to AppModel. Aco, Aro and AclNode now
extend Model instead of AppModel, which would cause an infinite loop. If your application depends on
having those models to extend AppModel for some reason, then copy AclNode to your application and have
it extend AppModel again.
Using the AclBehavior Most of the AclBehavior works transparently on your Model’s afterSave(). However, using it requires that your Model has a parentNode() method defined. This is used by the AclBehavior
to determine parent->child relationships. A model’s parentNode() method must return null or return a parent
Model reference:
public function parentNode() {
return null;
}

If you want to set an ACO or ARO node as the parent for your Model, parentNode() must return the alias of
the ACO or ARO node:
public function parentNode() {
return 'root_node';
}

A more complete example. Using an example User Model, where User belongsTo Group:
public function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
$data = $this->data;
if (empty($this->data)) {
$data = $this->read();
}
if (!$data['User']['group_id']) {
return null;
}
return array('Group' => array('id' => $data['User']['group_id']));
}

In the above example the return is an array that looks similar to the results of a model find. It is important
to have the id value set or the parentNode relation will fail. The AclBehavior uses this data to construct its
tree structure.
node() The AclBehavior also allows you to retrieve the Acl node associated with a model record. After
setting $model->id. You can use $model->node() to retrieve the associated Acl node.
You can also retrieve the Acl Node for any row, by passing in a data array:
$this->User->id = 1;
$node = $this->User->node();
$user = array('User' => array(
'id' => 1

General Purpose

367

CakePHP Cookbook Documentation, Release 2.x

));
$node = $this->User->node($user);

Will both return the same Acl Node information.
If you had setup AclBehavior to create both ACO and ARO nodes, you need to specify which node type you
want:
$this->User->id = 1;
$node = $this->User->node(null, 'Aro');
$user = array('User' => array(
'id' => 1
));
$node = $this->User->node($user, 'Aro');

Containable
class ContainableBehavior
A new addition to the CakePHP 1.2 core is the ContainableBehavior. This model behavior allows
you to filter and limit model find operations. Using Containable will help you cut down on needless wear
and tear on your database, increasing the speed and overall performance of your application. The class will
also help you search and filter your data for your users in a clean and consistent way.
Containable allows you to streamline and simplify operations on your model bindings. It works by temporarily or permanently altering the associations of your models. It does this by using the supplied containments
to generate a series of bindModel and unbindModel calls. Since Containable only modifies existing
relationships it will not allow you to restrict results by distant associations. Instead you should refer to
Joining tables.
To use the new behavior, you can add it to the $actsAs property of your model:
class Post extends AppModel {
public $actsAs = array('Containable');
}

You can also attach the behavior on the fly:
$this->Post->Behaviors->load('Containable');

Using Containable To see how Containable works, let’s look at a few examples. First, we’ll start off with
a find() call on a model named ‘Post’. Let’s say that ‘Post’ hasMany ‘Comment’, and ‘Post’ hasAndBelongsToMany ‘Tag’. The amount of data fetched in a normal find() call is rather extensive:
debug($this->Post->find('all'));
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article

368

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
[1] => Array
(
[id] => 2
[post_id] => 1
[author] => Sam
[email] => sam@example.net
[website] => http://example.net
[comment] => Second comment
[created] => 2008-05-18 00:00:00
)
)
[Tag] => Array
(
[0] => Array
(
[id] => 1
[name] => Awesome
)
[1] => Array
(
[id] => 2
[name] => Baking
)
)
)
[1] => Array
(
[Post] => Array
(...

For some interfaces in your application, you may not need that much information from the Post model. One
thing the ContainableBehavior does is help you cut down on what find() returns.
For example, to get only the post-related information, you can do the following:
$this->Post->contain();
$this->Post->find('all');

You can also invoke Containable’s magic from inside the find() call:
General Purpose

369

CakePHP Cookbook Documentation, Release 2.x

$this->Post->find('all', array('contain' => false));

Having done that, you end up with something a lot more concise:
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
)
[1] => Array
(
[Post] => Array
(
[id] => 2
[title] => Second article
[content] => bbb
[created] => 2008-05-19 00:00:00
)
)

This sort of help isn’t new: in fact, you can do that without the ContainableBehavior doing something
like this:
$this->Post->recursive = -1;
$this->Post->find('all');

Containable really shines when you have complex associations, and you want to pare down things that sit
at the same level. The model’s $recursive property is helpful if you want to hack off an entire level of
recursion, but not when you want to pick and choose what to keep at each level. Let’s see how it works by
using the contain() method.
The contain method’s first argument accepts the name, or an array of names, of the models to keep in the
find operation. If we wanted to fetch all posts and their related tags (without any comment information),
we’d try something like this:
$this->Post->contain('Tag');
$this->Post->find('all');

Again, we can use the contain key inside a find() call:
$this->Post->find('all', array('contain' => 'Tag'));

Without Containable, you’d end up needing to use the unbindModel() method of the model, multiple
times if you’re paring off multiple models. Containable creates a cleaner way to accomplish this same task.
Containing deeper associations Containable also goes a step deeper: you can filter the data of the associated models. If you look at the results of the original find() call, notice the author field in the Comment

370

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

model. If you are interested in the posts and the names of the comment authors — and nothing else — you
could do something like the following:
$this->Post->contain('Comment.author');
$this->Post->find('all');
// or..
$this->Post->find('all', array('contain' => 'Comment.author'));

Here, we’ve told Containable to give us our post information, and just the author field of the associated
Comment model. The output of the find call might look something like this:
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[author] => Daniel
[post_id] => 1
)
[1] => Array
(
[author] => Sam
[post_id] => 1
)
)
)
[1] => Array
(...

As you can see, the Comment arrays only contain the author field (plus the post_id which is needed by
CakePHP to map the results).
You can also filter the associated Comment data by specifying a condition:
$this->Post->contain('Comment.author = "Daniel"');
$this->Post->find('all');
//or...
$this->Post->find('all', array('contain' => 'Comment.author = "Daniel"'));

This gives us a result that gives us posts with comments authored by Daniel:

General Purpose

371

CakePHP Cookbook Documentation, Release 2.x

[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
)
)

There is an important caveat to using Containable when filtering on a deeper association. In the previous
example, assume you had 3 posts in your database and Daniel had commented on 2 of those posts. The
operation $this->Post->find(‘all’, array(‘contain’ => ‘Comment.author = “Daniel”’)); would return ALL
3 posts, not just the 2 posts that Daniel had commented on. It won’t return all comments however, just
comments by Daniel.
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
)
)

372

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

[1] => Array
(
[Post] => Array
(
[id] => 2
[title] => Second article
[content] => bbb
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
)
)
[2] => Array
(
[Post] => Array
(
[id] => 3
[title] => Third article
[content] => ccc
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 22
[post_id] => 3
[author] => Daniel
[email] => dan@example.com
[website] => http://example.com
[comment] => Another comment
[created] => 2008-05-18 00:00:00
)
)
)

If you want to filter the posts by the comments, so that posts without a comment by Daniel won’t be returned,
the easiest way is to find all the comments by Daniel and contain the Posts.
$this->Comment->find('all', array(
'conditions' => 'Comment.author = "Daniel"',
'contain' => 'Post'
));

Additional filtering can be performed by supplying the standard find options:
$this->Post->find('all', array('contain' => array(
'Comment' => array(
'conditions' => array('Comment.author =' => "Daniel"),
'order' => 'Comment.created DESC'
)
)));

General Purpose

373

CakePHP Cookbook Documentation, Release 2.x

Here’s an example of using the ContainableBehavior when you’ve got deep and complex model
relationships.
Let’s consider the following model associations:
User->Profile
User->Account->AccountSummary
User->Post->PostAttachment->PostAttachmentHistory->HistoryNotes
User->Post->Tag

This is how we retrieve the above associations with Containable:
$this->User->find('all', array(
'contain' => array(
'Profile',
'Account' => array(
'AccountSummary'
),
'Post' => array(
'PostAttachment' => array(
'fields' => array('id', 'name'),
'PostAttachmentHistory' => array(
'HistoryNotes' => array(
'fields' => array('id', 'note')
)
)
),
'Tag' => array(
'conditions' => array('Tag.name LIKE' => '%happy%')
)
)
)
));

Keep in mind that contain key is only used once in the main model, you don’t need to use ‘contain’ again
for related models.
Note: When using ‘fields’ and ‘contain’ options - be careful to include all foreign keys that your query
directly or indirectly requires. Please also note that because Containable must to be attached to all models
used in containment, you may consider attaching it to your AppModel.

ContainableBehavior options The ContainableBehavior has a number of options that can be set
when the Behavior is attached to a model. The settings allow you to fine tune the behavior of Containable
and work with other behaviors more easily.
• recursive (boolean, optional) set to true to allow containable to automatically determine the recursiveness level needed to fetch specified models, and set the model recursiveness to this level. setting
it to false disables this feature. The default value is true.
• notices (boolean, optional) issues E_NOTICES for bindings referenced in a containable call that are
not valid. The default value is true.

374

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

• autoFields: (boolean, optional) auto-add needed fields to fetch requested bindings. The default value
is true.
• order: (string, optional) the order of how the contained elements are sorted.
From the previous example, this is an example of how to force the posts to be ordered by the date when they
were last updated:
$this->User->find('all', array(
'contain' => array(
'Profile',
'Post' => array(
'order' => 'Post.updated DESC'
)
)
));

You can change ContainableBehavior settings at run time by reattaching the behavior as seen in Behaviors
(Using Behaviors).
ContainableBehavior can sometimes cause issues with other behaviors or queries that use aggregate functions and/or GROUP BY statements. If you get invalid SQL errors due to mixing of aggregate and nonaggregate fields, try disabling the autoFields setting.
$this->Post->Behaviors->load('Containable', array('autoFields' => false));

Using Containable with pagination By including the ‘contain’ parameter in the $paginate property
it will apply to both the find(‘count’) and the find(‘all’) done on the model.
See the section Using Containable for further details.
Here’s an example of how to contain associations when paginating:
$this->paginate['User'] = array(
'contain' => array('Profile', 'Account'),
'order' => 'User.username'
);
$users = $this->paginate('User');

Note: If you contained the associations through the model instead, it will not honor Containable’s recursive
option. So if you set recursive to -1 for example for the model, it won’t work:
$this->User->recursive = -1;
$this->User->contain(array('Profile', 'Account'));
$users = $this->paginate('User');

Translate
class TranslateBehavior

General Purpose

375

CakePHP Cookbook Documentation, Release 2.x

TranslateBehavior is actually quite easy to setup and works out of the box with very little configuration. In
this section, you will learn how to add and setup the behavior to use in any model.
If you are using TranslateBehavior in alongside containable issue, be sure to set the ‘fields’ key for your
queries. Otherwise you could end up with invalid SQL generated.
Initializing the i18n Database Tables You can either use the CakePHP console or you can manually
create it. It is advised to use the console for this, because it might happen that the layout changes in future
versions of CakePHP. Sticking to the console will make sure that you have the correct layout.
./cake i18n

Select [I] which will run the i18n database initialization script. You will be asked if you want to drop any
existing and if you want to create it. Answer with yes if you are sure there is no i18n table already, and
answer with yes again to create the table.
Attaching the Translate Behavior to your Models Add it to your model by using the $actsAs property
like in the following example.
class Post extends AppModel {
public $actsAs = array(
'Translate'
);
}

This will do nothing yet, because it expects a couple of options before it begins to work. You need to define
which fields of the current model should be tracked in the translation table we’ve created in the first step.
Defining the Fields You can set the fields by simply extending the ’Translate’ value with another
array, like so:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'fieldOne', 'fieldTwo', 'and_so_on'
)
);
}

After you have done that (for example putting “title” as one of the fields) you already finished the basic
setup. Great! According to our current example the model should now look something like this:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
}

376

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

When defining fields for TranslateBehavior to translate, be sure to omit those fields from the translated
model’s schema. If you leave the fields in, there can be issues when retrieving data with fallback locales.
Note: If all the fields in your model are translated be sure to add created and modified columns to
your table. CakePHP requires at least one non primary key field before it will save a record.

Conclusion From now on each record update/creation will cause TranslateBehavior to copy the value of
“title” to the translation table (default: i18n) along with the current locale. A locale is the identifier of the
language, so to speak.
Reading translated content By default the TranslateBehavior will automatically fetch
and add in data based on the current locale.
The current locale is read from
Configure::read(’Config.language’) which is assigned by the L10n class. You can
override this default on the fly using $Model->locale.
Retrieve translated fields in a specific locale By setting $Model->locale you can read translations
for a specific locale:
// Read the spanish locale data.
$this->Post->locale = 'es';
$results = $this->Post->find('first', array(
'conditions' => array('Post.id' => $id)
));
// $results will contain the spanish translation.

Retrieve all translation records for a field If you want to have all translation records attached to the
current model record you simply extend the field array in your behavior setup as shown below. The naming
is completely up to you.
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title' => 'titleTranslation'
)
);
}

With this setup the result of $this->Post->find() should look something like this:
Array
(
[Post] => Array
(
[id] => 1
[title] => Beispiel Eintrag
[body] => lorem ipsum...
[locale] => de_de
)

General Purpose

377

CakePHP Cookbook Documentation, Release 2.x

[titleTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Beispiel Eintrag
)
)
)

Note: The model record contains a virtual field called “locale”. It indicates which locale is used in this
result.
Note that only fields of the model you are directly doing ‘find‘ on will be translated. Models attached via associations won’t be translated because triggering callbacks on associated models is currently not supported.
Using the bindTranslation method You can also retrieve all translations, only when you need them, using
the bindTranslation method
TranslateBehavior::bindTranslation($fields, $reset)
$fields is a named-key array of field and association name, where the key is the translatable field and the
value is the fake association name.
$this->Post->bindTranslation(array('title' => 'titleTranslation'));
// need at least recursive 1 for this to work.
$this->Post->find('all', array('recursive' => 1));

With this setup the result of your find() should look something like this:
Array
(
[Post] => Array
(
[id] => 1
[title] => Beispiel Eintrag

378

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

[body] => lorem ipsum...
[locale] => de_de
)
[titleTranslation] => Array
(
[0] => Array
(
[id] => 1
[locale] => en_us
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Example entry
)
[1] => Array
(
[id] => 2
[locale] => de_de
[model] => Post
[foreign_key] => 1
[field] => title
[content] => Beispiel Eintrag
)
)
)

Saving in another language You can force the model which is using the TranslateBehavior to save in a
language other than the one detected.
To tell a model in what language the content is going to be you simply change the value of the $locale
property on the model before you save the data to the database. You can do that either in your controller or
you can define it directly in the model.
Example A: In your controller:
class PostsController extends AppController {
public function add() {
if (!empty($this->request->data)) {
// we are going to save the german version
$this->Post->locale = 'de_de';
$this->Post->create();
if ($this->Post->save($this->request->data)) {
return $this->redirect(array('action' => 'index'));
}
}
}
}

Example B: In your model:
General Purpose

379

CakePHP Cookbook Documentation, Release 2.x

class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Option 1) just define the property directly
public $locale = 'en_us';
// Option 2) create a simple method
public function setLanguage($locale) {
$this->locale = $locale;
}
}

Multiple Translation Tables If you expect a lot entries you probably wonder how to deal with a rapidly
growing database table. There are two properties introduced by TranslateBehavior that allow to specify
which “Model” to bind as the model containing the translations.
These are $translateModel and $translateTable.
Lets say we want to save our translations for all posts in the table “post_i18ns” instead of the default “i18n”
table. To do so you need to setup your model like this:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Use a different model (and table)
public $translateModel = 'PostI18n';
}

Note: It is important that you to pluralize the table. It is now a usual model and can be treated as such and
thus comes with the conventions involved. The table schema itself must be identical with the one generated
by the CakePHP console script. To make sure it fits one could just initialize a empty i18n table using the
console and rename the table afterwards.

Create the TranslateModel For this to work you need to create the actual model file in your models
folder. Reason is that there is no property to set the displayField directly in the model using this behavior
yet.
Make sure that you change the $displayField to ’field’.
class PostI18n extends AppModel {
public $displayField = 'field'; // important

380

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

}
// filename: PostI18n.php

That’s all it takes. You can also add all other model stuff here like $useTable. But for better consistency we could do that in the model which actually uses this translation model. This is where the optional
$translateTable comes into play.
Changing the Table If you want to change the name of the table you simply define $translateTable in
your model, like so:
class Post extends AppModel {
public $actsAs = array(
'Translate' => array(
'title'
)
);
// Use a different model
public $translateModel = 'PostI18n';
// Use a different table for translateModel
public $translateTable = 'post_translations';
}

Please note that you can’t use $translateTable alone.
If you don’t intend to use a custom
$translateModel then leave this property untouched. Reason is that it would break your setup and
show you a “Missing Table” message for the default I18n model which is created in runtime.
Tree
class TreeBehavior
It’s fairly common to want to store hierarchical data in a database table. Examples of such data might be
categories with unlimited subcategories, data related to a multilevel menu system or a literal representation
of hierarchy such as is used to store access control objects with ACL logic.
For small trees of data, or where the data is only a few levels deep it is simple to add a parent_id field to your
database table and use this to keep track of which item is the parent of what. Bundled with cake however,
is a powerful behavior which allows you to use the benefits of MPTT logic2 without worrying about any of
the intricacies of the technique - unless you want to ;).
Requirements To use the tree behavior, your database table needs 3 fields as listed below (all are ints):
• parent - default fieldname is parent_id, to store the id of the parent object
• left - default fieldname is lft, to store the lft value of the current row.
• right - default fieldname is rght, to store the rght value of the current row.
If you are familiar with MPTT logic you may wonder why a parent field exists - quite simply it’s easier to
do certain tasks if a direct parent link is stored on the database - such as finding direct children.
2

http://www.sitepoint.com/hierarchical-data-database-2/

General Purpose

381

CakePHP Cookbook Documentation, Release 2.x

Note: The parent field must be able to have a NULL value! It might seem to work if you just give the
top elements a parent value of zero, but reordering the tree (and possible other operations) will fail.

Basic Usage The tree behavior has a lot packed into it, but let’s start with a simple example - create the
following database table and put some data in it:
CREATE TABLE categories (
id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
parent_id INTEGER(10) DEFAULT NULL,
lft INTEGER(10) DEFAULT NULL,
rght INTEGER(10) DEFAULT NULL,
name VARCHAR(255) DEFAULT '',
PRIMARY KEY (id)
);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(1, 'My Categories', NULL, 1, 30);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(2, 'Fun', 1, 2, 15);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(3, 'Sport', 2, 3, 8);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(4, 'Surfing', 3, 4, 5);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(5, 'Extreme knitting', 3, 6, 7);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(6, 'Friends', 2, 9, 14);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(7, 'Gerald', 6, 10, 11);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(8, 'Gwendolyn', 6, 12, 13);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(9, 'Work', 1, 16, 29);

382

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

Chapter 7. Core Libraries

CakePHP Cookbook Documentation, Release 2.x

INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(10, 'Reports', 9, 17, 22);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(11, 'Annual', 10, 18, 19);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(12, 'Status', 10, 20, 21);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(13, 'Trips', 9, 23, 28);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(14, 'National', 13, 24, 25);
INSERT INTO
`categories` (`id`, `name`, `parent_id`,
VALUES
(15, 'International', 13, 26, 27);

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

`lft`, `rght`)

For the purpose of checking that everything is setup correctly, we can create a test method and output the
contents of our category tree to see what it looks like. With a simple controller:
class CategoriesController extends AppController {
public function index() {
$data = $this->Category->generateTreeList(
null,
null,
null,
'&nbsp;&nbsp;&nbsp;'
);
debug($data); die;
}
}

and an even simpler model definition:
// app/Model/Category.php
class Category extends AppModel {
public $actsAs = array('Tree');
}

We can check what our category tree data looks like by visiting /categories You should see something like
this:
• My Categories
– Fun

General Purpose

383

Running the above two code snippets would alter your tree as follows: • My Categories – Fun * Sport · Surfing · Extreme knitting · Skating New 384 Chapter 7. the tree behavior will add to the tree making your new addition a new top level entry: // pseudo controller code $data = array(). Release 2. $data['Category']['name'] = 'Skating'. If you don’t set the parent_id.CakePHP Cookbook Documentation. When using the tree behavior it’s not necessary to do any more than set the parent_id.x * Sport · Surfing · Extreme knitting * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International Adding data In the previous section. $this->Category->save($data). $data['Category']['name'] = 'Other People\'s Categories'. we used existing data and checked that it looked hierarchal via the method generateTreeList. However. usually you would add your data in exactly the same way as you would for any model. Core Libraries . For example: // pseudo controller code $data['Category']['parent_id'] = 3. and the tree behavior will take care of the rest. $this->Category->save($data).

neither does the data structure. If you modify something. The above code did not affect the parent_id field .even if the parent_id is included in the data that is passed to save if the value doesn’t change. For example: // pseudo controller code $this->Category->id = 5.the structure of your data will remain unchanged.x * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International • Other People’s Categories New Modifying data Modifying data is as transparent as adding new data. but do not change the parent_id field . Therefore the tree of data would now look like: • My Categories – Fun * Sport · Surfing · Extreme fishing Updated · Skating * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips General Purpose 385 . // id of Extreme knitting $this->Category->save(array('name' => 'Extreme fishing')). Release 2.CakePHP Cookbook Documentation.

For example with the following code: 386 Chapter 7. To remove it and any children it may have just call delete as you would for any model. Core Libraries . but instead should be located under Other People’s Categories. $this->Category->save(array('parent_id' => $newParentId)). As would be expected the structure would be modified to: • My Categories – Fun * Sport · Surfing · Skating * Friends · Gerald · Gwendolyn – Work * Reports · Annual · Status * Trips · National · International • Other People’s Categories – Extreme fishing Moved Deleting data The tree behavior provides a number of ways to manage deleting data.CakePHP Cookbook Documentation. Let’s say that Extreme fishing does not belong under Sport. // id of Extreme fishing $newParentId = $this->Category->field( 'id'. array('name' => 'Other People\'s Categories') ). To start with the simplest example. let’s say that the reports category is no longer useful. Release 2.x · National · International • Other People’s Categories Moving data around in your tree is also a simple affair. With the following code: // pseudo controller code $this->Category->id = 5.

$direct = false. $this->Category->delete(). $recursive = null) Parameters • $id – The ID of the record to look up • $direct – Set to true to return only the direct descendants • $fields – Single string field name or array of fields to include in the return • $order – SQL string of ORDER BY conditions General Purpose 387 . If you call find() and do not order by lft. Release 2. Note: Most tree behavior methods return and rely on data being sorted by the lft field. class TreeBehavior children($id = null. $limit = null. In addition to the core find methods. with the tree behavior there are a few more tree-orientated permutations at your disposal. The category tree would be modified as follows: • My Categories – Fun * Sport · Surfing · Skating * Friends · Gerald · Gwendolyn – Work * Trips · National · International • Other People’s Categories – Extreme fishing Querying and using your data Using and manipulating hierarchical data can be a tricky business. or call a tree behavior method and pass a sort order.CakePHP Cookbook Documentation.x // pseudo controller code $this->Category->id = 10. $fields = null. you may get undesirable results. $page = 1. $order = null.

or -$this->Category->id = 1. // a flat array with 11 items // -. // a flat array with 11 items // Only return direct children $directChildren = $this->Category->children(1. by default in the order they appear in the tree. Using the example data from the previous section: $totalChildren = $this->Category->childCount(1). childCount takes the primary key value (the id) of a row and returns how many children it has. • $spacer – The string to use in front of each item to indicate depth. The second optional parameter defines whether or not only direct children are counted. Core Libraries . $recursive=null) Parameters • $conditions – Uses the same conditional options as find().or -$this->Category->id = 1. $keyPath=null. // will output 11 // -. // a flat array with // 2 items Note: If you want a recursive array use find(’threaded’) childCount($id = null. $spacer= ‘_’. // will output 11 // Only counts the direct descendants of this category $numChildren = $this->Category->childCount(1. $direct = false) As with the method children. $valuePath=null. The second optional parameter defines whether or not only direct children should be returned. true). true). Using the example data from the previous section: $allChildren = $this->Category->children(1). // will output 2 generateTreeList($conditions=null. Release 2. • $valuePath – Path to the field to use for the label. $allChildren = $this->Category->children(). Below is an example of what you can expect this method to return: 388 Chapter 7. • $keyPath – Path to the field to use for the key.CakePHP Cookbook Documentation. • $recursive – The number of levels deep to fetch associated records This method will return data similar to find(‘list’) but with a nested prefix that is specified in the spacer option to show the structure of your data. $directChildren = $this->Category->childCount().x • $limit – SQL LIMIT statement • $page – for accessing paged results • $recursive – Number of levels deep for recursive associated Models The children method takes the primary key value (the id) of a row and returns the children.

"___Gerald". "___Gwendolyn". "_Work".x $treelist = $this->Category->generateTreeList(). Parameters • $results – Results of a find(‘all’) call. Output: array( [1] => [2] => [3] => [4] => [16] => [6] => [7] => [8] => [9] => [13] => [14] => [15] => [17] => [5] => ) "My Categories".title”. $results = $this->Category->formatTreeList($results. "__Friends". $options=array()) New in version 2. For example: $parent = $this->Category->getParentNode(2). Supported options are: •keyPath: A string path to the key.Post. //<. “{n}. "__Sport". "Other People's Categories". i. •spacer: The character or characters which will be repeated. array( 'spacer' => '--' )). "___National". return the parent node for any node.id for fun // $parent contains All categories General Purpose 389 .7. "__Trips". "___Skating". or false if the node has no parent (it’s the root node). as the name suggests. "___Surfing". An example would be: $results = $this->Category->find('all'). •valuePath: A string path to the value. "___International".Post. getParentNode() This convenience function will. "_Fun". "_Extreme fishing" formatTreeList($results.e.id”. i. This method will return data similar to find(‘list’) but with a nested prefix that is specified in the spacer option to show the structure of your data.e.CakePHP Cookbook Documentation. • $options – Options to pass into. “{n}. Release 2.

) => 1. *International Using the id of “International” getPath will return each of the parents in turn (starting from the top). [3] => array( 'Category' => array('id' ). $delta = null) { $this->Category->id = $id.. TreeBehavior::moveDown() Used to move a single node down the tree. All child nodes for the specified node will also be moved. . .) => 9. 'name' => 'International'. [1] => array( 'Category' => array('id' ).x getPath($id = null. } 390 Chapter 7.CakePHP Cookbook Documentation. –Work –Trips *. So for example the path from the category “International” is: •My Categories –..) Advanced Usage The tree behavior doesn’t only work in the background.) => 15.. Here is an example of a controller action (in a controller named Categories) that moves a specified node down the tree: public function movedown($id = null. [2] => array( 'Category' => array('id' ). Core Libraries . 'name' => 'My Categories'.. and any unexpected problems that might arise in the process. 'name' => 'Work'. // contents of $parents array( [0] => array( 'Category' => array('id' ). $fields = null. if (!$this->Category->exists()) { throw new NotFoundException(__('Invalid category')). $parents = $this->Category->getPath(15). Release 2.. $recursive = null) The ‘path’ when referring to hierarchal data is how you get from where you are to the top. there are a number of specific methods defined in the behavior to cater for all your hierarchical data needs. .. .) => 13.. 'name' => 'Trips'.. You need to provide the ID of the element to be moved and a positive number of how many positions the node should be moved down.

'be moved up. abs($delta)). which will be reparented one level higher.CakePHP Cookbook Documentation. You need to provide the ID of the element to be moved and a positive number of how many positions the node should be moved up.' ). Gerald. if you’d like to move the “Sport” ( id of 3 ) category one position down. Now the order of Friends will be Gwendolyn. All child nodes will also be moved. if (!$this->Category->exists()) { throw new NotFoundException(__('Invalid category')). } For example. } if ($delta > 0) { $this->Category->moveUp($this->Category->id. $delta = null) { $this->Category->id = $id. } return $this->redirect(array('action' => 'index')). Release 2. which for a model using the tree behavior will remove the specified node and all of its children. abs($delta)). } return $this->redirect(array('action' => 'index')). It offers more control than delete. TreeBehavior::moveUp() Used to move a single node up the tree. } else { $this->Session->setFlash( 'Please provide the number of positions the field should be' . } else { $this->Session->setFlash( 'Please provide a number of positions the category should' . if you would like to move the category “Gwendolyn” ( id of 8 ) up one position you would request /categories/moveup/8/1.' ). you would request: /categories/movedown/3/1. 'moved down. Taking the following tree as a starting point: • My Categories – Fun General Purpose 391 . TreeBehavior::removeFromTree($id = null. } For example. Here’s an example of a controller action (in a controller named Categories) that moves a node up the tree: public function moveup($id = null. $delete = false) Using this method will either delete or move a node but retain its sub-tree.x if ($delta > 0) { $this->Category->moveDown($this->Category->id.

//which field to use in reordering. default: 'ASC' 392 Chapter 7. ‘field’ => $Model->displayField. The Sport node will be become a top level node: • My Categories – Fun * Surfing * Extreme knitting * Skating • Sport Moved This demonstrates the default behavior of removeFromTree of moving the node to have no parent. Release 2. //direction to order. default: $Model->displayField 'field' => . ‘order’ => ‘ASC’.CakePHP Cookbook Documentation. and re-parenting all children. The tree would become • My Categories – Fun * Surfing * Extreme knitting * Skating This demonstrates the alternate use for removeFromTree. Core Libraries . $model->reorder(array( //id of record to use as top node for reordering. This method does not change the parent of any node. the children have been reparented and ‘Sport’ has been deleted. If however the following code snippet was used with the id for ‘Sport’: $this->Node->removeFromTree($id. default: $Model->id 'id' => .x * Sport · Surfing · Extreme knitting · Skating Running the following code with the id for ‘Sport’: $this->Node->removeFromTree($id). true). ‘verify’ => true)) Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters. TreeBehavior::reorder(array(‘id’ => null.

CakePHP Cookbook Documentation. TreeBehavior::reorder($options = array()) Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters. Data Integrity Due to the nature of complex self referential data structures such as trees and linked lists. The missingParentAction parameter only applies to “parent” mode and determines what to do if the parent field contains an id that is not present. default: true 'verify' => )).do nothing and carry on • ’return’ . if the MPTT fields are corrupt or empty. //whether or not to verify the tree before reorder. Reordering affects all nodes in the tree by default. E. The opposite source of data will be populated based upon that source of info. // Rebuild all the parent_id's based on the lft and rght fields $this->Category->recover('tree').g.use the existing parent_id‘s to update the lft and rght fields • ’tree’ . they can occasionally become broken by a careless call. // or $this->Category->recover('parent'). Note: If you have saved your data or made other operations on the model. you might want to set $model->id = null before calling reorder.x 'order' => . however the following options can affect the process: General Purpose 393 . TreeBehavior::recover($mode = ‘parent’. $missingParentAction = null) The mode parameter is used to specify the source of info that is valid/correct. with the $mode ’parent’ the values of the parent_id field will be used to populate the left and right fields. for all is not lost! The Tree Behavior contains several previously undocumented features designed to recover from such situations.delete the node • int .use the existing lft and rght fields to update parent_id Available missingParentActions options when using mode=’parent’: • null . Available $mode options: • ’parent’ . Take heart. Otherwise only the current node and it’s children will be reordered.do nothing and return • ’delete’ . Release 2.set the parent_id to this id Example: // Rebuild all the left and right fields based on the parent_id $this->Category->recover(). This method does not change the parent of any node.

'order' => 'ASC'. default is the displayField for the model.whether or not to verify the tree prior to resorting. message) • type is either ’index’ or ’node’ • ’id’ is the id of the erroneous node. • ’verify’ . 'field' => $model->displayField. Example output: Array ( [0] => Array ( [0] => [1] => [2] => ) [1] => Array ( [0] => [1] => [2] => ) [10] => Array ( [0] => [1] => [2] => ) 394 node 3 left and right values identical node 2 The parent node 999 doesn't exist index 123 missing Chapter 7. Release 2.field to use for sorting. • ’field‘ . ’DESC’ for descending sort.only reorder nodes below this node. $options is used to pass all extra parameters. • ’order’ . Each record in the output array is an array of the form (type.CakePHP Cookbook Documentation. • ’message’ depends on the error Example Use: $this->Category->verify().x • ’id’ . Core Libraries . id.’ASC’ for ascending. with fields for type. and has the following possible keys by default. all of which are optional: array( 'id' => null. 'verify' => true ) TreeBehavior::verify() Returns true if the tree is valid otherwise an array of errors. incorrect index and message.

CakePHP Cookbook Documentation. } This example shows how a Category model could be managed in a tree structure using the TreeBehavior. Some behaviors may require or allow settings to be defined when the behavior is attached to the model. children(): $kids = $this->Category->children().g.7. no level saving )). Release 2. we tell our TreeBehavior the names of the “left” and “right” fields in the underlying database table: class Category extends AppModel { public $actsAs = array('Tree' => array( 'left' => 'left_node'. } General Purpose 395 . You can use the level option to specify the field that will save level of each node: public $actAs = array('Tree' => array( 'level' => 'level'. // Defaults to null. you can use this method to get level of a particular node. Knowing the depth of tree nodes can be useful when you want to retrieve nodes only upto a certain level for e. TreeBehavior::getLevel($id) New in version 2. Once a behavior has been specified. use the methods added by the behavior as if they always existed as part of the original model: // Set ID $this->Category->id = 42.7. If you are not caching the level of nodes using the level option in settings.x [99] => Array ( [0] => node [1] => 163 [2] => left greater than right ) ) Node Level (Depth) New in version 2. Using Behaviors Behaviors are attached to models through the $actsAs model class variable: class Category extends AppModel { public $actsAs = array('Tree'). i. // Use behavior method. Here. when generating menus. 'right' => 'right_node' )).e.

There’s no reason why. we are looking to disable the behavior from acting upon our CakePHP model callbacks. our saves. In fact. } So far we have been adding behaviors to models using a model class variable. Say that our familiar Category model needs to start behaving as a Christmas model. Release 2. we may need to “detach” behaviors from our models at runtime. 396 Chapter 7.CakePHP Cookbook Documentation.x We can also attach several behaviors to a model. we can also attach new behaviors. That means that our behaviors will be attached to our models throughout the model’s lifetime. for example. it may also need internationalization support: class Category extends AppModel { public $actsAs = array( 'Tree' => array( 'left' => 'left_node'. } Just as we could completely detach a behavior from a model at runtime. Instead of detaching the behavior. our Category model should only behave as a tree. we then tell our model to stop informing of these callbacks to the Translate behavior: // Stop letting the behavior handle our model callbacks $this->Category->Behaviors->disable('Translate'). 'Translate' ). and if not we then restore its ability to react to them: // If our behavior is not handling model callbacks if (!$this->Category->Behaviors->enabled('Translate')) { // Tell it to start doing so $this->Category->Behaviors->enable('Translate'). which is acting as a Tree and a Translate model. etc. array('left' => 'new_left_node')). to just disable the Translate behavior from acting upon our normal model operations: our finds. 'right' => 'right_node' ). We may need. We may also need to find out if our behavior is handling those model callbacks. } We can also use the load method to override behavior settings: // We will change one setting from our already attached behavior $this->Category->Behaviors->load('Tree'. Let’s say that on our previous Category model. That will make our Category model stop behaving as a Translate model from thereon. instead. Core Libraries . we need for some reason to force it to stop acting as a Translate model: // Detach a behavior from our model: $this->Category->Behaviors->unload('Translate'). but only on Christmas day: // If today is Dec 25 if (date('m/d') === '12/25') { // Our model needs to behave as a Christmas model $this->Category->Behaviors->load('Christmas'). However.

There’s also a method to obtain the list of behaviors a model has attached. General Purpose 397 .x And using aliasing. When created behaviors will have their setup() method called: public function setup(Model $Model. They are named in CamelCase and postfixed by Behavior. Every callback and behavior method takes a reference to the model it is being called from as the first parameter. A quick example that illustrates how behavior settings can be passed from the model to the behavior: class Post extends AppModel { public $actsAs = array( 'YourBehavior' => array( 'option1_key' => 'option1_value' ) ). 'option2_key' => 'option2_default_value'.CakePHP Cookbook Documentation. it’s a good practice to store the settings per alias/model name that is using the behavior. afterFind.php. afterValidate. Besides implementing the callbacks. The callbacks are similar to those found in Models: beforeFind. we can customize the alias it will be loaded as. beforeValidate. If we pass the name of a behavior to the method. afterSave. NameBehavior. ). Information about specifying settings can be found in the chapters about core behaviors and their configuration. } Since behaviors are shared across all the model instances that use them. also allowing it to be loaded multiple times with different settings: // The behavior will be available as 'MyTree' $this->Category->Behaviors->load('MyTree'. } Creating Behaviors Behaviors that are attached to Models get their callbacks called automatically. otherwise it will give us the list of attached behaviors: // If the Translate behavior is not attached if (!$this->Category->Behaviors->loaded('Translate')) { // Get the list of all behaviors the model has attached $behaviors = $this->Category->Behaviors->loaded(). you can add settings per behavior and/or model behavior attachment. array('className' => 'Tree')). Release 2. afterDelete and onError see Callback Methods. Find them in lib/Cake/Model/Behavior/. beforeSave. 'option3_key' => 'option3_default_value'. beforeDelete. $settings = array()) { if (!isset($this->settings[$Model->alias])) { $this->settings[$Model->alias] = array( 'option1_key' => 'option1_default_value'. Your behaviors should be placed in app/Model/Behavior. It’s often helpful to use a core behavior as a template when creating your own. ex. it will tell us if that behavior is attached to the model.

For example: $this->Duck->fly('toronto'.CakePHP Cookbook Documentation. but the called method name will be the 2nd parameter. This allows you to munge the method name for additional information. All other supplied parameters are shifted one place to the right. Behaviors can also define mapped methods. } Keep in mind that methods called in a $this->doIt() fashion from inside a behavior method will not get the $model parameter automatically appended. As you can see. When creating behavior methods you automatically get passed a reference of the calling model as the first parameter. This allows you to create methods similar to Model::findAllByXXX methods on your behaviors. $arg2) { debug(func_get_args()). $to) { // Do some flying. The method signature for a mapped method is slightly different than a normal behavior mixin method: class MyBehavior extends ModelBehavior { public $mapMethods = array('/do(\w+)/' => 'doSomething'). Although this method takes two parameters. For example if you had: class Duck extends AppModel { public $actsAs = array('Flying'). $arg1. 'lenny' 398 Chapter 7. //do something } } The above will map every doXXX() method call to the behavior. Core Libraries . $from. public function doSomething(Model $model. Mapped methods need to be declared in your behaviors $mapMethods array. } You would be able to call FlyingBehavior methods as if they were methods on your Duck model. Release 2. 'lenny'). behaviors can also provide pattern matching methods. the method signature should look like: public function fly(Model $Model. much like Model::findAllByXX. Mapped methods use pattern matching for method invocation.x } $this->settings[$Model->alias] = array_merge( $this->settings[$Model->alias]. } Creating behavior methods Behavior methods are automatically available on any model acting as the behavior. the model is still the first parameter. // would output 'ReleaseTheHounds'. (array)$settings). 'montreal'). If the above behavior was attached to a model the following would happen: $model->doReleaseTheHounds('karl'. $method. Mapped methods In addition to providing ‘mixin’ methods. 'karl'.

Much like regular behavior methods.x Behavior callbacks Model Behaviors can define a number of callbacks that are triggered before the model callbacks of the same name. ModelBehavior::cleanup(Model $Model) Called when a behavior is detached from a model. ModelBehavior::afterValidate(Model $Model) You can use afterValidate to perform any data cleanup or preparation if needed. General Purpose 399 . The return value will be passed on as the results to either the next behavior in the chain or the model’s afterFind. The base method removes model settings based on $model->alias. array $settings = array()) Called when a behavior is attached to a model. ModelBehavior::beforeValidate(Model $Model. Returning an array will augment the query parameters used for the find operation. mixed $results. Return true to allow it continue. All behavior callbacks are fired before the model callbacks are: • beforeFind • afterFind • beforeValidate • afterValidate • beforeSave • afterSave • beforeDelete • afterDelete Creating a behavior callback class ModelBehavior Model behavior callbacks are defined as simple methods in your behavior class. ModelBehavior::beforeSave(Model $Model. ModelBehavior::setup(Model $Model. ModelBehavior::beforeFind(Model $Model. Returning false from a beforeValidate callback will abort the validation and cause it to fail. This parameter is the model that the behavior method was invoked on. Release 2. The settings come from the attached model’s $actsAs property.CakePHP Cookbook Documentation. You can override this method and provide custom cleanup functionality. boolean $primary = false) You can use the afterFind to augment the results of a find. array $options = array()) You can return false from a behavior’s beforeSave to abort the save. array $query) If a behavior’s beforeFind return’s false it will abort the find(). they receive a $Model parameter as the first argument. Behavior callbacks allow your behaviors to capture events in attached models and augment the parameters or splice in additional behavior. array $options = array()) You can use beforeValidate to modify a model’s validate array or handle any other pre-validation logic. ModelBehavior::afterFind(Model $Model.

Some examples of components requiring configuration are Authentication and Cookie. $this->Auth->loginAction = array( 'controller' => 'users'. Each of the core components is detailed in its own chapter. ModelBehavior::beforeDelete(Model $Model. is usually done in the $components array or your controller’s beforeFilter() method: class PostsController extends AppController { public $components = array( 'Auth' => array( 'authorize' => array('controller'). Configuration for these components. and false when a record is updated. This section describes how to configure and use components. ModelBehavior::afterDelete(Model $Model) You can use afterDelete to perform clean up operations related to your behavior. Release 2. The above could also be expressed as: public function beforeFilter() { $this->Auth->authorize = array('controller'). All core components allow their configuration settings to be set in this way. Components Components are packages of logic that are shared between controllers. boolean $created. boolean $cascade = true) You can return false from a behavior’s beforeDelete to abort the delete. Core Libraries . 'Cookie' => array('name' => 'CookieMonster') ). Return true to allow it continue. This is useful when you need to assign the results of a function to a component property. If you find yourself wanting to copy and paste things between controllers. and for components in general. The previous fragment of code would be an example of configuring a component with the $components array. 'loginAction' => array( 'controller' => 'users'.CakePHP Cookbook Documentation.x ModelBehavior::afterSave(Model $Model. you can configure components in your controller’s beforeFilter() method. See Components. Configuring Components Many of the core components require configuration. $this->Cookie->name = 'CookieMonster'. $created will be true when a record is created. and how to create your own components. } 400 Chapter 7. In addition. array $options = array()) You can use afterSave to perform clean up operations related to your behavior. You can also create your own components. CakePHP comes with a fantastic set of core components you can use to aid in various common tasks. you should consider creating your own component to contain the functionality. Creating components keeps controller code clean and allows you to reuse code between projects. 'action' => 'login' ) ). 'action' => 'login' ).

you could access them like so: class PostsController extends AppController { public $components = array('Session'.Toolbar' => array('panels' => array('history'. One common setting to use is the className option.x It’s possible. Be sure to not give a component and a model the same name. } } Note: Since both Models and Components are added to Controllers as properties they share the same ‘namespace’. which allows you to alias components. using them is pretty simple. Release 2. To this end. General Purpose 401 .CakePHP Cookbook Documentation. however. including inside other Components. Each component you use is exposed as a property on your controller. some components allow configuration options be set in the $components array: public $components = array( 'DebugKit.id')) { $this->Session->setFlash('Post deleted. } // app/Controller/Component/MyAuthComponent. class MyAuthComponent extends AuthComponent { // Add your code to override the core AuthComponent } The above would alias MyAuthComponent to $this->Auth in your controllers. If you had loaded up the SessionComponent and the CookieComponent in your controller. Using Components Once you’ve included some components in your controller. return $this->redirect(array('action' => 'index')).php class PostsController extends AppController { public $components = array( 'Auth' => array( 'className' => 'MyAuth' ) ). 'Controller/Component').'). This feature is useful when you want to replace $this->Auth or another common Component reference with a custom implementation: // app/Controller/PostsController. 'Cookie').php App::uses('AuthComponent'. public function delete() { if ($this->Post->delete($this->request->data('Post. that a component requires certain configuration options to be set before the controller’s beforeFilter() is run. 'session')) ). Consult the relevant documentation to determine what configuration options each component provides. Note: Aliasing a component replaces that instance anywhere that component is used.

Create the file in app/Controller/Component/MathComponent. $amount2) { return $amount1 + $amount2. The first step is to create a new component file and class.CakePHP Cookbook Documentation. The controller will automatically be given a new attribute named after the component. These parameters can then be handled by the Component: 402 Chapter 7.php. Creating a Component Suppose our online application needs to perform a complex mathematical operation in many different parts of the application. 'Controller'). When including Components in a Controller you can also declare a set of parameters that will be passed on to the Component’s constructor. we can use it in the application’s controllers by placing the component’s name (without the “Component” part) in the controller’s $components array. If the component you are calling has this method you will need to call it manually after load.x Loading components on the fly You might not need all of your components available on every controller action. Failing to do this will trigger an exception. Core Libraries . 'Session'). Component Callbacks Components also offer a few request life-cycle callbacks that allow them to augment the request cycle. class MathComponent extends Component { public function doComplexOperation($amount1. See the base Component API for more information on the callbacks components offer. So there is no need to re-declare the same component twice. Including your component in your controllers Once our component is finished. Note: Keep in mind that loading a component on the fly will not call its initialize method. Release 2. The basic structure for the component would look something like this: App::uses('Component'. Components declared in AppController will be merged with those in your other controllers. We could create a component to house this shared logic for use in many different controllers. through which we can access an instance of it: /* Make the new component available at $this->Math. as well as the standard $this->Session */ public $components = array('Math'. } } Note: All components must extend Component. $this->OneTimer->getTime(). From inside a controller’s method you can do the following: $this->OneTimer = $this->Components->load('OneTimer'). In situations like this you can load a component at runtime using the Component Collection.

public function initialize(Controller $controller) { $this->Existing->foo(). In this case you can include other components in your component the exact same way you include them in controllers ..using the $components var: // app/Controller/Component/CustomComponent. 'Session'.. 'Auth' ).CakePHP Cookbook Documentation. } } // app/Controller/Component/ExistingComponent. Using other Components in your Component Sometimes one of your components may need to use another component.. It also provides prototypes for all the component callbacks. class ExistingComponent extends Component { public function foo() { // . By convention.php App::uses('Component'.php App::uses('Component'. } } Note: In contrast to a component included in a controller no callbacks will be triggered on a component’s component. 'Controller'). 'Controller'). class CustomComponent extends Component { // the other component your component uses public $components = array('Existing'). if array keys match component’s public properties. General Purpose 403 . the properties will be set to the values of these keys. The above would pass the array containing precision and randomGenerator to MathComponent::__construct() as the second parameter. Component API class Component The base Component class offers a few methods for lazily loading other Components through ComponentCollection as well as dealing with common handling of settings. Release 2. 'randomGenerator' => 'srand' ).x public $components = array( 'Math' => array( 'precision' => 2.. } public function bar() { // .

Helpers Helpers are the component-like classes for the presentation layer of your application. times and numbers. If this method returns false the controller will not continue on to redirect the request. Component::beforeRedirect(Controller $controller. Instead. $status and $exit variables have same meaning as for the controller’s method. This creates a big savings in processing time for each request to a cached URL as minimal code is executed. $settings = array()) Constructor for the base component class. The CacheHelper then uses helper callbacks to process the file and output to generate the cache file. Core Libraries . and outline the basic tasks CakePHP’s core helpers can help you accomplish. It should be noted that the Cache helper works quite differently than other helpers. View Caching in CakePHP temporarily stores parsed layouts and views as simple PHP + HTML files. All $settings that are also public properties will have their values changed to the matching value in $settings. but before the controller’s renders views and layout. and can even speed up AJAX functionality. Callbacks Component::initialize(Controller $controller) Is called before the controller’s beforeFilter method. Any nocache blocks are processed normally and the view is served. or the cache has expired for the requested URL it continues to process the request normally. Release 2. Component::shutdown(Controller $controller) Is called before output is sent to the browser. 404 Chapter 7. or layouts. elements. This chapter will show you how to create your own helpers. Component::beforeRender(Controller $controller) Is called after the controller executes the requested action’s logic. saving time repetitively retrieving data. Component::startup(Controller $controller) Is called after the controller’s beforeFilter method but before the controller executes the current action handler. They contain presentational logic that is shared between many views.x Component::__construct(ComponentCollection $collection. If it has. a view is marked with cache tags indicating which blocks of content should not be cached. You can also return a string which will be interpreted as the URL to redirect to or return an associative array with the key ‘url’ and optionally ‘status’ and ‘exit’. check out the chapter for each helper: CacheHelper class CacheHelper(View $view. For more information on the helpers included in CakePHP. If CakePHP doesn’t find a cached view. It does not have methods that are directly called. aid in formatting text. $url. CakePHP checks to see if that request string has already been cached. They assist in creating well-formed markup (including forms). The $url. the rest of the URL dispatching process is skipped. When a URL is requested. $exit=true) Is invoked when the controller’s redirect method is called but before any further action. $status=null.CakePHP Cookbook Documentation. CakePHP features a number of helpers that aid in view creation. array $settings = array()) The Cache helper assists in caching entire layouts and views.

check. array( 'CacheDispatcher' )). controller beforeFilter. 'duration' => 36000).filters'. This will cache the view action 10 hours. 'add' => array('callbacks' => true. $cacheAction should be set to an array which contains the actions you want cached. and generate view cache files when handling requests. Release 2. To do so you must use the array format for $cacheAction and create an array like the following: public $cacheAction = array( 'view' => array('callbacks' => true. Using the example of an ArticlesController. 'index' => array('callbacks' => true. to store the view cache files prefixed. This is done through the $cacheAction variable in your controllers. First in your APP/Config/core. The time value can be expressed in a strtotime() format (e. Additionally. Once you’ve uncommented the Cache. 'index' => 48000 ). This is also the reason it is disabled by default. 'duration' => 48000) ).CakePHP Cookbook Documentation. } You will also need to add the CacheDispatcher to your dispatcher filters in your bootstrap: Configure::write('Dispatcher. fire the component initialize.g.3: If you have a setup with multiple domains or languages you can use Configure::write(‘Cache. You can also enable controller/component callbacks for cached views created with CacheHelper. 'duration' => 21600). By setting callbacks => true you tell CacheHelper that you want the generated files to create the components and models for the controller. Additional configuration options CacheHelper has a few additional configuration options you can use to tune and tweak its behavior. By making $cacheAction a strtotime() friendly value you can cache every action in the controller: public $cacheAction = "1 hour". ‘YOURPREFIX’). “1 hour”. that receives a lot of traffic that needs to be cached: public $cacheAction = array( 'view' => 36000. and the index action 13 hours. Note: Setting callbacks => true partly defeats the purpose of caching. and component startup callbacks. and the duration in seconds you want those views cached.check line you will need to add the helper to your controller’s $helpers array: class PostsController extends AppController { public $helpers = array('Cache').x Using the Helper There are two steps you have to take before you can use the CacheHelper.viewPrefix’. General Purpose 405 .php uncomment the Configure write call for Cache. This will tell CakePHP to check for. New in version 2. or “3 minutes”).

?> <!--/nocache--> Note: You cannot use nocache tags in elements. ?>. and there has been an INSERT. Note: This automatic cache clearing requires the controller/model name to be part of the URL. certain parts of the page may look different whether a user is currently logged in or browsing your site as a guest. The FlashHelper replaces the flash() method on SessionHelper and should be used instead of that method. If you’ve used routing to change your URLs this feature will not work.x Marking Non-Cached Content in Views There will be times when you don’t want an entire view cached. Flash elements are found under the app/View/Elements/Flash directory. You’ll notice that CakePHP’s App template comes with two flash elements: success. To indicate blocks of content that are not to be cached. For example. array $config = array()) FlashHelper provides a way to render flash messages that were set in $_SESSION by FlashComponent. This will clear all cached data. and new content is generated on the next request. Warning: If you have view variables that contain un-serializable content such as SimpleXML objects.CakePHP Cookbook Documentation. If you need to clear the cached view files. 'users/login').ctp. FlashComponent and FlashHelper primarily use elements to render flash messages.name')): ?> Welcome. wrap them in <!--nocache--> <!--/nocache--> like so: <!--nocache--> <?php if ($this->Session->check('User. the cache for that view is cleared. use clearCache().ctp and error. When a cache file is created. Release 2. <?php else: ?> <?php echo $this->Html->link('Login'. and view variables are serialized with PHP’s serialize(). If you need to manually clear the cache. 406 Chapter 7.name')). FlashHelper class FlashHelper(View $view. It should be noted that once an action is cached. the request object. or DELETE query made to a Post. resource handles. excluding cached view files. ?> <?php endif. Since there are no callbacks around elements. <?php echo h($this->Session->read('User. Clearing the Cache It is important to remember that CakePHP will clear a cached view if a model used in the cached view is modified. or closures you might not be able to use view caching. Core Libraries . the controller method for the action will not be called. they cannot be cached. UPDATE. For example. you can do so by calling Cache::clear(). if a cached view uses data from the Post model.

you can specify which flash key to render: <?php echo $this->Flash->render('other') ?> You can also override any of the options that were set in FlashComponent: // In your Controller $this->Flash->set('The user has been saved. FormHelper class FormHelper(View $view.x Rendering Flash Messages To render a flash message. But. or you can use specific methods to get only what you need. array( 'element' => 'great_success' )). // In your View: Will use great_success. you should escape it with h when formatting your messages. The form element is also returned with a DOM ID.ctp <?php echo $this->Flash->render('flash'. If create() is called with no parameters supplied. Creating Forms The first method you’ll need to use in order to take advantage of the FormHelper is create(). The FormHelper focuses on creating forms quickly. array $options = array()) All parameters are optional. I’d see something like the following output in the rendered view: <form id="UserAddForm" method="post" action="/users/add"> Note: data into General Purpose You can also pass false for $model. If I were to call create() inside a UsersController view. via the current URL.CakePHP Cookbook Documentation. it assumes you are building a form that submits to the current controller. CakePHP does not escape the HTML in flash messages. array( 'element' => 'success' )). Release 2. array $settings = array()) The FormHelper does most of the heavy lifting in form creation. If you are using any request or user data in your flash messages. The FormHelper is also flexible . This special method outputs an opening form tag. FormHelper::create(string $model = null. CakePHP uses a “flash” key for flash messages in a session. you can simply use FlashHelper’s render() method: <?php echo $this->Flash->render() ?> By default.it will do almost everything for you using conventions. For more information about the available array options. if you’ve specified a key when setting the flash message in FlashComponent. please refer to the FlashComponent section. re-population and layout. and the name of the controller action. in a way that will streamline validation.ctp instead of success. The ID is generated using the name of the model.'. The default method for form submission is POST. CamelCased. This will place your form the array: $this->request->data (instead of in the sub-array: 407 . Note: By default.

The FormHelper uses the $this->request->data property to automatically detect whether to create an add or edit form. Release 2. 408 Chapter 7. If you do not specify a model. All fields are assumed to belong to this model (unless otherwise specified). Output: <form id="RecipeAddForm" method="post" action="/recipes/add"> This will POST the form data to the add() action of RecipesController.php: public function edit($id = null) { if (empty($this->request->data)) { $this->request->data = $this->Recipe->findById($id).com/recipes/edit/5. you are creating that form’s context. ?> Output: <form id="RecipeEditForm" method="post" action="/recipes/edit/5"> <input type="hidden" name="_method" value="PUT" /> Note: Since this is an edit form. you can also use the same logic to create an edit form. The $options array is where most of the form configuration happens. you can specify a model name. we would get the following: // Controller/RecipesController. and all models referenced are assumed to be associated with it.ctp: // Since $this->request->data['Recipe']['id'] = 5. then it assumes you are using the default model for the current controller: // If you are on /recipes/add echo $this->Form->create('Recipe'). If $this->request->data contains an array element named after the form’s model. if we browse to http://site. However. and that array contains a non-empty value of the model’s primary key. This can be handy for short forms that may not The create() method allows us to customize much more using the parameters. } else { // Save logic goes here } } // View/Recipes/edit.CakePHP Cookbook Documentation. you should always use plugin syntax when creating a form. then the FormHelper will create an edit form for that record. This special array can contain a number of different key-value pairs that affect the way the form tag is generated. This will ensure the form is correctly generated: echo $this->Form->create('ContactManager. // we will get an edit form <?php echo $this->Form->create('Recipe'). First. represent anything in your database. Core Libraries .x $this->request->data[’Model’]). By specifying a model for a form.Contact'). a hidden input field is generated to override the default HTTP method. For example. When creating forms for models in plugins. however.

This is to be used if there are any file elements inside the form. your form will be functionally equivalent to a ‘post’ form. Release 2. array('type' => 'file')). Supplying either ‘post’ or ‘get’ changes the form submission method accordingly: echo $this->Form->create('User'. if you’d like to point the form to the login() action of the current controller. respectively. Options for create() There are a number of options for create(): • $options[’type’] This key is used to specify the type of form to be created. The absence of the proper enctype attribute will cause the file uploads not to function: echo $this->Form->create('User'. This allows CakePHP to emulate proper REST support in web browsers. Output: <form id="UserAddForm" method="get" action="/users/add"> Specifying ‘file’ changes the form submission method to ‘post’. but when submitted.x Changed in version 2. array('type' => 'get')). is now the current URL including passed. you would supply an $options array like the following: echo $this->Form->create('User'. 'action' => 'add') )). Output: General Purpose 409 . and querystring parameters. ‘get’. You can override this default by supplying $options[’url’] in the second parameter of $this->Form->create(). Valid values include ‘post’.0: The default URL for all forms. named. and includes an enctype of “multipart/form-data” on the form tag. Output: <form id="UserAddForm" enctype="multipart/form-data" method="post" action="/users/add"> When using ‘put’ or ‘delete’. Output: <form id="UserLoginForm" method="post" action="/users/login"> • $options[’url’] If the desired form action isn’t in the current controller. The supplied URL can be relative to your CakePHP application: echo $this->Form->create(null. ‘put’ and ‘delete’. • $options[’action’] The action key allows you to point the form to a specific action in your current controller. ‘file’. array('action' => 'login')). you can specify a URL for the form action using the ‘url’ key of the $options array. For example. array( 'url' => array('controller' => 'recipes'.CakePHP Cookbook Documentation. the HTTP request method will be overridden with ‘PUT’ or ‘DELETE’.

CakePHP Cookbook Documentation. array( 'inputDefaults' => array( 'label' => false. Output: <form method="get" action="http://www. Release 2.google. but using end() also allows the FormHelper to insert needed hidden form elements that SecurityComponent requires: <?php echo $this->Form->create(). • $options[’inputDefaults’] You can declare a set of default options for input() with the inputDefaults key to customize your default input creation: echo $this->Form->create('User'. $secureAttributes = array()) The FormHelper includes an end() method that completes the form. Core Libraries . If the form is meant to be submitted via AJAX. the form’s submit action is changed so that pressing the submit button does not submit the form. • $options[’default’] If ‘default’ has been set to boolean false. Closing the Form FormHelper::end($options = null. // No div. ?> <!-.x <form method="post" action="/recipes/add"> or can point to an external domain: echo $this->Form->create(null.com/search'. 'type' => 'get' )).Form elements go here --> <?php echo $this->Form->end(). Often.com/search"> Also check HtmlHelper::url() method for more examples of different types of URLs. setting ‘default’ to false suppresses the form’s default behavior so you can grab the data and submit it via AJAX instead. All inputs created from that point forward would inherit the options declared in inputDefaults. array('label' => 'Username') ).google. ?> 410 Chapter 7. end() only outputs a closing form tag. 'div' => false ) )). array( 'url' => 'http://www. You can override the defaultOptions by declaring the option in the input() call: echo $this->Form->input('password'). no label // has a label element echo $this->Form->input( 'username'.

?> Will output: <div class="submit"> <input type="submit" value="Finish" /> </div> </form> You can specify detail settings by passing an array to end(): $options = array( 'label' => 'Update'.5: The $secureAttributes parameter was added in 2. Creating form elements There are a few ways to create form inputs with the FormHelper.org/2. We’ll start by looking at input(). echo $this->Form->end($options). ) ).html General Purpose 411 . FormHelper::input(string $fieldName.cakephp. Internally input() delegates to other methods in FormHelper. The type of input created depends on the column datatype: Column Type Resulting Form Field 3 http://api.5. Release 2.field: •Wrapping div.CakePHP Cookbook Documentation. This method will automatically inspect the model field it has been supplied in order to create an appropriate input for that field. Will output: <div class="glass-pill"><input type="submit" value="Update" name="Update"> </div> See the Form Helper API3 for further details. array $options = array()) Creates the following elements given a particular Model.8/class-FormHelper. •Label element •Input element(s) •Error element with message if applicable. Changed in version 2. Note: If you are using SecurityComponent in your application you should always end your forms with end().x If a string is supplied as the first parameter to end(). 'div' => array( 'class' => 'glass-pill'. the FormHelper outputs a submit button named accordingly along with the closing form tag: <?php echo $this->Form->end('Finish').

timestamp day.CakePHP Cookbook Documentation. For example. One limitation of this behavior is the field’s model must have been loaded during this request. echo $this->Form->input('approved'). month. etc. with name of email email text. and meridian selects time hour. telephone. year. Or be directly associated to the model supplied to create(). minute. minute. Release 2. To skip browser validation triggering for the whole form you can set option ’formnovalidate’ => true for the input button you generate using FormHelper::submit() or set ’novalidate’ => true in options for FormHelper::create().3 the HTML5 required attribute will also be added to the input based on validation rules. with name of tel. and meridian selects binary file The $options parameter allows you to customize how input() works. year. //meridian //textarea echo $this->Form->end('Add'). array( 'label' => 'Date of birth'. varchar. hour. Since 2. minute.x string (char.3. The wrapping div will have a required class name appended if the validation rules for the Model’s field do not specify allowEmpty => true. tinyint(1) checkbox text textarea text. with name of password. or psword password text. let’s assume that your User model includes fields for a username (varchar).) text boolean. New in version 2. New in version 2. hour. echo $this->Form->input('password').70. echo $this->Form->input('username'). Core Libraries . and finely control what is generated. password (varchar). or phone tel date day. //text //password //day. 'dateFormat' => 'DMY'. approved (datetime) and quote (text). passwd. You can explicitly set required key in options array to override it for a field. echo $this->Form->input('quote'). month. and year selects datetime. 412 Chapter 7. You can use the input() method of the FormHelper to create appropriate inputs for all of these form fields: echo $this->Form->create(). month.5: The binary type now maps to a file input. A more extensive example showing some options for a date field: echo $this->Form->input('birth_dt'. 'minYear' => date('Y') .

Relation. $this->User->Group->find('list')). you can specify any option for the input type & any HTML attribute (for instance onfocus). If $fields is null all fields. Afterwards. In the controller action you would put the following: $this->set('groups'. Use FormHelper::inputs(mixed $fields = null.CakePHP Cookbook Documentation. $this->UserGroup->find('list')). And in the view a multiple select can be created with this simple code: echo $this->Form->input('Group'). Would generate an input set with a custom legend.x 'maxYear' => date('Y') . You can customize individual inputs through $fields as well. add the following to your form-view: echo $this->Form->input('group_id'). or ExtraFunkyModel -> extraFunkyModels) with the select options. “UserGroup”. General Purpose 413 . If you want to create a select field while using a belongsTo . In addition to controller fields output.g. // or $this->set( 'reallyInappropriateModelNames'. $options = array()) Generate a set of inputs for $fields. $this->ReallyInappropriateModelName->find('list') ). Besides the specific options for input() found below. except of those defined in $blacklist. If your model name consists of two or more words..18. In addition to fields control. For more information on $options and $htmlAttributes see HtmlHelper. Assuming that User hasAndBelongsToMany Group. $this->User->Group->find('list')). e. you can add the following to your Users-controller (assuming your User belongsTo Group): $this->set('groups'. of the current model will be used. inputs() allows you to use a few additional options. set a camelCase plural variable (group -> groups in this case. echo $this->Form->inputs(array( 'name' => array('label' => 'custom label') )). )). when passing the data using set() you should name your data in a pluralised and camelCased format as follows: $this->set('userGroups'. $fields can be used to control legend and fieldset rendering with the fieldset and legend keys. Note: Try to avoid using FormHelper::input() to generate submit buttons.or hasOne . Release 2. $this->Form->inputs(array(’legend’ => ’My legend’)). FormHelper::submit() instead. array $blacklist = null. In your controller.

You can create inputs for associated models. In addition to the field types found in the Creating form elements.year'. echo $this->Form->input('email'. and any type supported by HTML5: echo $this->Form->input('field'. it’ll automatically use the current model name to build an input with a format like the following: <input type="text" id="ModelnameFieldname" name="data[Modelname][fieldname]"> This allows you to omit the model name when generating inputs for the model that the form was created for. you can set the name attribute to override the default behavior: echo $this->Form->input('Model. Or supply a string to customize the legend text. day. thus creating an array that can be saved in one shot with saveAll(). Core Libraries .0.fieldname'). as well as HTML attributes. or meridian and having issues getting the correct input. Output: <input type="text" id="Modelname0Fieldname" name="data[Modelname][0][fieldname]"> <input type="text" id="Modelname1Fieldname" name="data[Modelname][1][fieldname]"> FormHelper uses several field-suffixes internally for datetime input creation. minute.fieldname'). echo $this->Form->input('Modelname. In addition to its own options input() accepts options for the generated input types. Options FormHelper::input() supports a large number of options. •legend Set to false to disable the legend for the generated input set. array('type' => 'file')). Whenever you specify a field name with the form helper methods. The following will cover the options specific to FormHelper::input(). month. If a string is supplied it will be used as the class name for the fieldset element.fieldname as the first parameter: echo $this->Form->input('Modelname. ‘password’. 'name' => 'data[Model][year]' )). If you need to specify multiple fields using the same field name. by specifying a type. array('type' => 'email')). Release 2. overriding model introspection. use the following convention: echo $this->Form->input('Modelname. array( 'type' => 'text'. Field naming conventions The Form helper is pretty smart. you can also create ‘file’. hour. or arbitrary models by passing in Modelname. 414 Chapter 7.CakePHP Cookbook Documentation.x •fieldset Set to false to disable the fieldset. • $options[’type’] You can force the type of an input.1.fieldname'). If you are using fields named year.

name'. Using a string value will set the div’s class name.CakePHP Cookbook Documentation. Alternatively. array( 'div' => array( 'id' => 'mainDiv'.name'. 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: echo $this->Form->input('User. array('div' => false)). you can set this key to false to disable the output of the div.x Output: <div class="input file"> <label for="UserField">Field</label> <input type="file" name="data[User][field]" value="" id="UserField" /> </div> <div class="input email"> <label for="UserEmail">Email</label> <input type="email" name="data[User][email]" value="" id="UserEmail" /> </div> • $options[’div’] Use this option to set attributes of the input’s containing div. array( 'div' => 'class_name' )). ?> Output: <label for="UserName">Name</label> <input name="data[User][name]" type="text" value="" id="UserName" /> General Purpose 415 . Release 2. Setting the class name: echo $this->Form->input('User.name'. An array will set the div’s attributes to those specified by the array’s keys/values. 'title' => 'Div Title'. 'style' => 'display:block' ) )). Output: <div class="class_name"> <label for="UserName">Name</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> Setting multiple attributes: echo $this->Form->input('User.

x • $options[’label’] Set this key to the string you would like to be displayed within the label that usually accompanies the input: echo $this->Form->input('User. Core Libraries . array( 'label' => array( 'class' => 'thingy'. Release 2. array('errorMessage' => false)). set this key to false to disable the output of the label: echo $this->Form->input('User. To modify the wrapping element type and its class. Output: <div class="input"> <label for="UserName" class="thingy">The User Alias</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> • $options[’error’] Using this key allows you to override the default model error messages and can be used. If you do this. use the following format: 416 Chapter 7. for example.name'.CakePHP Cookbook Documentation. to set i18n messages. Output: <div class="input"> <label for="UserName">The User Alias</label> <input name="data[User][name]" type="text" value="" id="UserName" /> </div> Alternatively. but retain the field classes.name'. array('label' => false)). array('error' => false)). set the errorMessage key to false: $this->Form->input('Model. 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. array( 'label' => 'The User Alias' )). To disable only the error message.field'.name'. To disable error message output & field classes set the error key to false: $this->Form->input('Model. you can use a text key in the array to customize the label text: echo $this->Form->input('User. 'text' => 'The User Alias' ) )). It has a number of suboptions which control the wrapping element. wrapping element class name.field'. and whether HTML in the error message will be escaped.

array( 'before' => '--before--'. 'between' => '--between---'. $options[’separator’].field'. array( 'error' => array( 'attributes' => array('wrap' => 'span'. To prevent HTML being automatically escaped in the error message output. array( 'error' => array( 'attributes' => array('escape' => false) ) )). 'class' => 'bzzz') ) )). 'after' => '--after--'. New in version 2. General Purpose 417 .CakePHP Cookbook Documentation. set the escape suboption to false: $this->Form->input('Model.field'. In addition you can provide i18n messages for your forms. array( 'error' => array('tooShort' => __('This is not long enough')) )). To override the model error messages use an array with the keys matching the validation rule names: $this->Form->input('Model.3 • $options[’before’]. As seen above you can set the error message for each validation rule you have in your models. '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> For radio inputs the ‘separator’ attribute can be used to inject markup to separate each input/label pair: echo $this->Form->input('field'.3: Support for the errorMessage option was added in 2. array( 'before' => '--before--'. 'separator' => '--separator--'. and Use these keys if you need to inject some markup inside the output of the input() method: echo $this->Form->input('field'.x $this->Form->input('Model.field'. $options[’after’] $options[’between’]. 'after' => '--after--'. Release 2.

Core Libraries . array( 'inputDefaults' => array( 'label' => false. The ‘format’ options supports an array of strings describing the template you would like said element to follow. ’after’. • $options[’format’] The ordering of the HTML generated by FormHelper is controllable as well.’error’). // has a label element echo $this->Form->input('username'. GET Form Inputs When using FormHelper to generate inputs for GET forms.Tags'. array('multiple' => true)). 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> For date and datetime type elements the ‘separator’ attribute can be used to change the string between select elements. you can use inputDefaults‘ to keep your code dry: echo $this->Form->create('User'. 'div' => false ) )). Defaults to ‘-‘. For example: // Makes <input name="email" type="text" /> echo $this->Form->input('User. '2') )). no label echo $this->Form->input('password'). 418 Chapter 7.x 'options' => array('1'. array('label' => 'Username')). ’input’. If you need to later change the defaults you can use FormHelper::inputDefaults(). You can override the defaultOptions by declaring the option in the input() call: // No div. Release 2.CakePHP Cookbook Documentation.email'). // Makes <select name="Tags" multiple="multiple"> echo $this->Form->input('Tags. the input names will automatically be shortened to provide more human friendly names. All inputs created from that point forward would inherit the options declared in inputDefaults. The supported array keys are: array(’before’. ’between’. ’label’. • $options[’inputDefaults’] If you find yourself repeating the same options in multiple input() calls.

email'. In addition to the above options. 'm' => 'Medium'. 'default' => 'm') ). 'l' => 'Large'). A false value is used to disable/exclude options of an input field. and applied to the generated HTML input element. Generating specific types of inputs In addition to the generic input() method. Example with select field (Size “Medium” will be selected as default): $sizes = array('s' => 'Small'. These can be used to generate just the input widget itself. and combined with other methods like label() and error() to generate fully custom form layouts. Note: You cannot use default to check a checkbox . To reduce repetition the common options shared by all input methods are as follows: • $options[’class’] You can set the class name for an input: echo $this->Form->input('title'. you can mixin any HTML attribute you wish to use. array('options' => $sizes. echo $this->Form->input( 'size'. array('name' => 'data[User][email]')). FormHelper has specific methods for generating a number of different types of inputs. • $options[’id’] Set this key to force the value of the DOM id for the input. All of these options are also supported by input(). • $options[’default’] Used to set a default value for the input field. array('default' => 'Sugar')). Example usage: echo $this->Form->input('ingredient'. Any non-special option name will be treated as an HTML attribute. 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). Common options Many of the various input element methods support a common set of options. Date and datetime fields’ default values can be set by using the ‘selected’ key.instead you might set the value in $this->request->data in your controller. Release 2. Instead use ’default’ => 0.CakePHP Cookbook Documentation. array('class' => 'custom-class')). Options for select. or set the input option checked to true. checkbox and radio inputs General Purpose 419 .x If you want to override the generated name attributes you can use the name option: // Makes the more typical <input name="data[User][email]" type="text" /> echo $this->Form->input('User. Beware of using false to assign a default value. so ’default’ => false would not set any value at all.

pass in a string to empty: echo $this->Form->input('field'. this creates a blank option with an empty value in your drop down list. 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> Note: If you need to set the default value in a password field to blank. datetime). 'empty' => '(choose one)' )). array( 'options' => array(1.CakePHP Cookbook Documentation. Note: The selected key for date and datetime inputs may also be a UNIX timestamp. 'DMY'.x • $options[’selected’] Used in combination with a select-type input (i. A list of key-value pairs can be supplied for a date or datetime field: echo $this->Form->dateTime('Contact. use ‘value’ => ‘’ instead. Set ‘selected’ to the value of the item you wish to be selected by default when the input is rendered: echo $this->Form->input('close_time'. For types select. date. 2.date'. forces the input to remain empty. Core Libraries . 5). 'minute' => 'MINUTE'. array( 'type' => 'time'. 'selected' => '13:30:00' )). 'month' => 'MONTH'. 'hour' => 'HOUR'. When passed to a select list. array( 'empty' => array( 'day' => 'DAY'.e. time. '12'. • $options[’empty’] If set to true. 4. If you want to have a empty value with text displayed instead of just a blank option. 'year' => 'YEAR'. 'meridian' => false ) ) ). Output: 420 Chapter 7. 3. Release 2.

. <option value="12">December</option> </select> .... and the primary colors would be overridden: General Purpose 421 .<select name="data[Contact][date][month]" id="ContactDateMonth"> <option value="">MONTH</option> <option value="01">January</option> // . array('hiddenField' => false)). <option value="59">59</option> </select> <select name="data[Contact][date][meridian]" id="ContactDateMeridian"> <option value="am">am</option> <option value="pm">pm</option> </select> • $options[’hiddenField’] For certain input types (checkboxes. <option value="12">12</option> </select>:<select name="data[Contact][date][min]" id="ContactDateMin"> <option value="">MINUTE</option> <option value="00">00</option> // . If the hidden input is on the page in multiple places. radios) a hidden input is created so that the key in $this->request->data will exist even without a value specified: <input type="hidden" name="data[Post][Published]" id="PostPublished_" value="0" /> <input type="checkbox" name="data[Post][Published]" value="1" id="PostPublished" /> This can be disabled by setting the $options[’hiddenField’] = false: echo $this->Form->checkbox('published'.. Release 2. only the last group of input’s values will be saved In this example. only the tertiary colors would be passed.CakePHP Cookbook Documentation. <option value="31">31</option> </select> . <option value="1996">1996</option> </select> <select name="data[Contact][date][hour]" id="ContactDateHour"> <option value="">HOUR</option> <option value="01">1</option> // .. Which outputs: <input type="checkbox" name="data[Post][Published]" value="1" id="PostPublished" /> If you want to create multiple blocks of inputs on a form that are all grouped together.<select name="data[Contact][date][year]" id="ContactDateYear"> <option value="">YEAR</option> <option value="2036">2036</option> // .....x <select name="data[Contact][date][day]" id="ContactDateDay"> <option value="">DAY</option> <option value="01">1</option> // . you should use this parameter on all inputs except the first.

Release 2. Valid values include any combination of ‘D’. • $options[’dateFormat’] Used to specify the format of the select inputs for a date-related set of inputs. Valid values include ‘asc’. 24. • $options[’interval’] This option specifies the number of minutes between each option in the minutes select box: 422 Chapter 7. $options[’maxYear’] Used in combination with a date/datetime input. • $options[’orderYear’] Used in combination with a date/datetime input. • $options[’minYear’]. Defines the lower and/or upper end of values shown in the years select field. Defines the order in which the year values will be set.CakePHP Cookbook Documentation. Core Libraries . Datetime options • $options[’timeFormat’] Used to specify the format of the select inputs for a time-related set of inputs.x <h2>Primary Colors</h2> <input type="hidden" name="data[Color][Color]" id="Colors_" value="0" /> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsRed" /> <label for="ColorsRed">Red</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsBlue" /> <label for="ColorsBlue">Blue</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsYellow" /> <label for="ColorsYellow">Yellow</label> <h2>Tertiary Colors</h2> <input type="hidden" name="data[Color][Color]" id="Colors_" value="0" /> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsGreen" /> <label for="ColorsGreen">Green</label> <input type="checkbox" name="data[Color][Color][]" value="5" id="ColorsPurple" /> <label for="ColorsPurple">Purple</label> <input type="checkbox" name="data[Addon][Addon][]" value="5" id="ColorsOrange" /> <label for="ColorsOrange">Orange</label> Disabling the ’hiddenField’ on the second input group would prevent this behavior. and null. )). ‘desc’. 'hiddenField' => 'N'. The default value is ‘desc’. ‘M’ and ‘Y’ or null. Valid values include 12. array( 'value' => 'Y'. You can set a different hidden field value other than 0 such as ‘N’: echo $this->Form->checkbox('published'. The inputs will be put in the order defined by the dateFormat option.

Output: <label for="UserName" id="user-label">Name</label> <label for="UserName" class="highlight">Your username</label> FormHelper::text(string $name.name'. $fieldName is used for generating the DOM id. Defaults to null which rounds half up according to interval. Ex: name=data[User][username]. string $text. $fieldName will be used to inflect the label’s text: echo $this->Form->label('User.name'). however. id=UserUsername FormHelper::label(string $fieldName. Form Element-Specific Methods All elements are created under a form for the User model as in the examples above. array $options) Create a label element. the HTML code generated will contain attributes that reference to the User model.name'. 'highlight'). New in version 2. array('class' => 'users')).x echo $this->Form->input('Model. One for each 15 minutes. General Purpose 423 . Many of these methods also make use of a special $options parameter. null.time'. Output: <label for="UserName">Name</label> <label for="UserName">Your username</label> $options can either be an array of HTML attributes. Release 2.CakePHP Cookbook Documentation. For this reason. array $options) Creates a password field. echo $this->Form->label('User. or a string that will be used as a class name: echo $this->Form->label('User. 'Your username'). array $options) The rest of the methods available in the FormHelper are for creating specific form elements. echo $this->Form->label('User. $options is used primarily to specify HTML tag attributes (such as the value or DOM id of an element in the form): echo $this->Form->text('username'. 'interval' => 15 )). array( 'type' => 'time'. Will output: <input name="data[User][username]" type="text" class="users" id="UserUsername" /> FormHelper::password(string $fieldName. If $text is undefined. In this case. Would create 4 options in the minute select. • $options[’round’] Can be set to up or down to force rounding in either direction.4. 'Your username'. array('id' => 'user-label')).name'.

array('escape' => false). the array $this->request->data will contain the information saved for the User model).. Example: <textarea name="data[User][notes]" id="UserNotes"> This text is to be edited. Example: echo $this->Form->hidden('id'). the error-field class name will be applied. Defaults to true. echo $this->Form->textarea('notes'. </textarea> Note: The textarea input type allows for the $options attribute of ’escape’ which determines whether or not the contents of the textarea should be escaped. the value corresponding to id field will automatically be added to the HTML generated. Will output: <input name="data[User][id]" id="UserId" type="hidden" /> If the form is edited (that is. the array $this->request->data will contain the information saved for the User model).x echo $this->Form->password('password').CakePHP Cookbook Documentation. FormHelper::textarea(string $fieldName. echo $this->Form->textarea('notes')..0: Hidden fields no longer remove the class attribute. the value corresponding to notes field will automatically be added to the HTML generated. Will output: <input name="data[User][password]" value="" id="UserPassword" type="password" /> FormHelper::hidden(string $fieldName. Options 424 Chapter 7. Core Libraries . echo $this->Form->input( 'notes'. array('type' => 'textarea'. Example for data[User][id] = 10: <input name="data[User][id]" id="UserId" type="hidden" value="10" /> Changed in version 2. // OR. 'escape' => false) ). array $options) Creates a hidden form input. Will output: <textarea name="data[User][notes]" id="UserNotes"></textarea> If the form is edited (that is. This means that if there are validation errors on hidden fields.. Release 2. array $options) Creates a textarea input field.

array $options) Creates a checkbox form element. 'cols' => '5') ).g. echo $this->Form->checkbox('done'). Output: <textarea name="data[Form][textarea]" cols="5" rows="5" id="FormTextarea"> </textarea> FormHelper::checkbox(string $fieldName. Release 2. •$attributes[’between’] specify some content to be inserted between the legend and first element. This method also generates an associated hidden form input to force the submission of data for the specified field. $options[’cols’] These two keys specify the number of rows and columns: echo $this->Form->textarea( 'textarea'. array $attributes) Creates a set of radio button inputs. Will output: <input type="hidden" name="data[User][done]" value="0" id="UserDone_" /> <input type="checkbox" name="data[User][done]" value="555" id="UserDone" /> If you don’t want the Form helper to create a hidden input: echo $this->Form->checkbox('done'. <br />). textarea() supports a few specific options: •$options[’rows’].x In addition to the Common options. •$attributes[’separator’] to specify HTML in between radio buttons (e. •$attributes[’disabled’] Setting this to true or ’disabled’ will disable all of the generated radio buttons. array $options. Will output: <input type="hidden" name="data[User][done]" value="0" id="UserDone_" /> <input type="checkbox" name="data[User][done]" value="1" id="UserDone" /> It is possible to specify the value of the checkbox by using the $options array: echo $this->Form->checkbox('done'. General Purpose 425 . array('hiddenField' => false)). array('value' => 555)). array('rows' => '5'.CakePHP Cookbook Documentation. Will output: <input type="checkbox" name="data[User][done]" value="1" id="UserDone" /> FormHelper::radio(string $fieldName. Options •$attributes[’value’] to set which value should be selected default.

5)). Release 2. array $attributes) Creates a select element. $attributes = array('legend' => false). $options = array('M' => 'Male'. $attributes). Set $attributes[’legend’] to false to remove them. setting $attributes[’value’] to a selected value or boolean false will do just that.1: The $attributes[’disabled’] option was added in 2. 'F' => 'Female').4. echo $this->Form->select('gender'. populated with the items in $options. array $options. with the option specified by $attributes[’value’] shown as selected by default. Core Libraries . $options. Set the ‘empty’ key in the $attributes variable to false to turn off the default empty option: $options = array('M' => 'Male'. or for a radio group. FormHelper::select(string $fieldName. Defaults to true: $options = array('M' => 'Male'. 'F' => 'Female'). array(1. Unless the ‘type’ is specified as ‘radio’.2. echo $this->Form->radio('gender'. 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. echo $this->Form->select('gender'. the FormHelper will assume that the target output is a select input: echo $this->Form->select('field'. Will output: <select name="data[User][gender]" id="UserGender"> <option value=""></option> <option value="M">Male</option> <option value="F">Female</option> </select> The select input type allows for a special $option attribute called ’escape’ which accepts a bool and determines whether to HTML entity encode the contents of the select options. array('escape' => false)).3. •$attributes[’options’] This key allows you to manually specify options for a select input. $options. Output: 426 Chapter 7.x •$attributes[’legend’] Radio elements are wrapped with a legend and fieldset by default.CakePHP Cookbook Documentation. 'F' => 'Female').1. Changed in version 2. $options).

This works on multiple checkboxes and radio buttons too. Output: <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> If you would like to generate a select with optgroups. 'Group 2' => array( 'Value 3' => 'Label 3' ) ). Output: <select name="data[User][field]" id="UserField"> <optgroup label="Group 1"> <option value="Value 1">Label 1</option> <option value="Value 2">Label 2</option> </optgroup> <optgroup label="Group 2"> <option value="Value 3">Label 3</option> </optgroup> </select> •$attributes[’multiple’] If ‘multiple’ has been set to true for an input that outputs a select. but instead of optgroups wraps elements in fieldsets: $options = array( 'Group 1' => array( 'Value 1' => 'Label 1'. the select will allow multiple selections: General Purpose 427 . just pass data in hierarchical format.x <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> Options can also be supplied as key-value pairs: echo $this->Form->select('field'. echo $this->Form->select('field'. 'Value 2' => 'Label 2'. $options). 'Value 3' => 'Label 3' )).CakePHP Cookbook Documentation. Release 2. array( 'Value 1' => 'Label 1'. 'Value 2' => 'Label 2' ).

Alternatively set ‘multiple’ to ‘checkbox’ to output a list of related check boxes: $options = array( 'Value 1' => 'Label 1'. 'Value 2' => 'Label 2' ). array('multiple' => true) ).x echo $this->Form->select( 'Model. this option can be set to disable all or some checkboxes. array( 'multiple' => 'checkbox'. Output: <div class="input select"> <label for="ModelField">Field</label> <input name="data[Model][field]" value="" id="ModelField" type="hidden"> <div class="checkbox"> <input name="data[Model][field][]" disabled="disabled" 428 Chapter 7. echo $this->Form->select('Model. echo $this->Form->select('Model. 'Value 2' => 'Label 2' ). Release 2. Core Libraries .field'.field'. $options. $options. $options. 'disabled' => array('Value 1') )). To disable all checkboxes set disabled to true: $options = array( 'Value 1' => 'Label 1'. array( 'multiple' => 'checkbox' )).CakePHP Cookbook Documentation. Output: <div class="input select"> <label for="ModelField">Field</label> <input name="data[Model][field]" value="" id="ModelField" type="hidden"> <div class="checkbox"> <input name="data[Model][field][]" value="Value 1" id="ModelField1" type="checkbox"> <label for="ModelField1">Label 1</label> </div> <div class="checkbox"> <input name="data[Model][field][]" value="Value 2" id="ModelField2" type="checkbox"> <label for="ModelField2">Label 2</label> </div> </div> •$attributes[’disabled’] When creating checkboxes.field'.

FormHelper::file(string $fieldName. Next add either of the two lines to your form view file: echo $this->Form->input('Document.pdf'. array( 'between' => '<br />'. 'size' => 41737.3: Support for arrays in $attributes[’disabled’] was added in 2.file-upload General Purpose 429 . ). array( 'enctype' => 'multipart/form-data' )).x value="Value 1" id="ModelField1" type="checkbox"> <label for="ModelField1">Label 1</label> </div> <div class="checkbox"> <input name="data[Model][field][]" value="Value 2" id="ModelField2" type="checkbox"> <label for="ModelField2">Label 2</label> </div> </div> Changed in version 2. array('type' => 'file')). This array is generated by PHP itself. it is not possible to put default values into input fields of type ‘file’. Due to the limitations of HTML itself. 'error' => 0. the values in the submitted data array would be organized as follows. you must first make sure that the form enctype is set to “multipart/form-data”.submittedfile'.tmp'. file fields provide an expanded data array to the script receiving the form data. array $options) To add a file upload field to a form. 'type' => 'application/pdf'. // OR echo $this->Form->file('Document. so for more detail on the way PHP handles data passed via file fields read the PHP manual section on file uploads4 . if the CakePHP was installed on a Windows server. the value inside will be empty.net/features. Upon submission.submittedfile'). For the example above. 'tmp_name' => 'C:/WINDOWS/TEMP/php1EE. 4 http://php. so start off with a create function such as the following: echo $this->Form->create('Document'. Release 2. Each time the form is displayed.3. // OR echo $this->Form->create('Document'. 'type' => 'file' )).CakePHP Cookbook Documentation. ‘tmp_name’ will have a different path in a Unix environment: $this->request->data['Document']['submittedfile'] = array( 'name' => 'conference_schedule.

Core Libraries . array $options) Creates a submit button with caption $caption. array('type' => 'file')). remember to set the form encoding-type. Will output: <form enctype="multipart/form-data" method="post" action="/users/add"> <input name="data[User][avatar]" value="" id="UserAvatar" type="file"> Note: When using $this->Form->file(). } return false. $options[’type’] will output one of the three possible button types: 430 Setting Chapter 7. 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. If the supplied $caption is a URL to an image (it contains a ‘. you can avoid this by declaring $options[’div’] = false: echo $this->Form->submit().’ character). } Creates a file input: echo $this->Form->create('User'.CakePHP Cookbook Documentation. Will output: <div class="submit"><input type="image" src="/img/ok.png"></div> FormHelper::button(string $title. echo $this->Form->submit('ok. echo $this->Form->file('avatar'). array $options = array()) Creates an HTML button with the specified title and a default type of “button”.x Validating Uploads Below is an example validation method you could define in your model to validate whether a file has been successfully uploaded: public function isUploadedFile($params) { $val = array_shift($params). by setting the type option to ‘file’ in $this->Form->create() Creating buttons and submit elements FormHelper::submit(string $caption.png'). the submit button will be rendered as an image. Release 2. if ((isset($val['error']) && $val['error'] == 0) || (!empty( $val['tmp_name']) && $val['tmp_name'] != 'none') ) { return is_uploaded_file($val['tmp_name']). It is enclosed between div tags by default.

FormHelper::postButton(string $title. instead of returning with the link. Requires JavaScript to be enabled in browser.(the default). you must use the inline or block options so that the new form can be rendered outside of its parent. $this->Form->button('Another Button'. Changed in version 2. but access the URL using method POST. $this->Form->button('Submit Form'. array( 'type' => 'submit'.3: The method option was added. which accepts a bool and determines whether to HTML entity encode the $title of the button. This method creates a <form> element.CakePHP Cookbook Documentation. This helps avoiding nested form tags. Use confirm key in $options instead.button: Creates a standard push button. Defaults to false: echo $this->Form->button('Submit Form'.5: The inline and block options were added.submit: Same as the $this->Form->submit method . Will output: <button <button <button <button type="submit">A Button</button> type="button">Another Button</button> type="reset">Reset the Form</button> type="submit">Submit Form</button> The button input type supports the escape option. Changed in version 2.6: The argument $confirmMessage was deprecated. echo echo echo echo $this->Form->button('A Button'). Changed in version 2. So do not use this method in some opened form. Instead use FormHelper::submit() or FormHelper::button() to create buttons inside opened forms. Release 2. mixed $url = null.reset: Creates a form reset button. If you want to use this method inside of an existing form. if you want to use a custom block you can specify it using the block option instead. Setting ’inline’ => false will add the form tag to the postLink content block. FormHelper::postLink(string $title. array $options = array ()) Creates an HTML link. mixed $url. 'escape' => true )). If all you are looking for is a button to submit your form. array('type' => 'button')). 2. 3. then you should use FormHelper::submit() instead. array('type' => 'reset')).x 1. This method creates a <form> element. They allow buffering the generated form tag. $this->Form->button('Reset the Form'. array $options = array ()) Create a <button> tag with a surrounding <form> that submits via POST. array('type' => 'submit')). General Purpose 431 .

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> 432 Chapter 7. $dateFormat = ‘DMY’. HTML attributes may be supplied in $attributes.x Creating date and time inputs FormHelper::dateTime($fieldName. You can specify not to display empty values by setting “array(‘empty’ => false)” in the attributes parameter. int $maxYear. It will also pre-select the fields with the current datetime. date('Y')). int $minYear. ‘MDY’. array $attributes) Creates a select element populated with the years from $minYear to $maxYear. ‘YMD’ or ‘NONE’. 2000. Core Libraries . the select will not include an empty option: echo $this->Form->year('purchased'. $timeFormat = ‘12’. FormHelper::year(string $fieldName. Release 2. If $attributes[’empty’] is false. array $attributes) Creates a select element populated with month names: echo $this->Form->month('mob'). ‘24’.CakePHP Cookbook Documentation. Valid values for $timeFormat are ‘12’. and null. Valid values for $dateformat are ‘DMY’. 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> <option value="2004">2004</option> <option value="2003">2003</option> <option value="2002">2002</option> <option value="2001">2001</option> <option value="2000">2000</option> </select> FormHelper::month(string $fieldName. $attributes = array()) Creates a set of select inputs for date and time.

x You can pass in your own array of months to be used by setting the ‘monthNames’ attribute.. •‘wrap’ mixed Whether or not the error message should be wrapped in a div. array $attributes) Creates a select element populated with the hours of the day. Release 2. or have months displayed as numbers by passing false. <option value="31">31</option> </select> FormHelper::hour(string $fieldName. array $options) Shows a validation error message. Options: •‘escape’ bool Whether or not to HTML escape the contents of the error. mixed $text. specified by $text.CakePHP Cookbook Documentation.): echo $this->Form->month('mob'. if ($this->Form->isFieldError('gender')) { echo $this->Form->error('gender'). in the event that a validation error has occurred. •‘class’ string The class name for the error message FormHelper::isFieldError(string $fieldName) Returns true if the supplied $fieldName has an active validation error. will be used as the HTML tag to use. for the given field. boolean $format24Hours. FormHelper::day(string $fieldName.g. To create an empty option with prompt text of your choosing (e. FormHelper::meridian(string $fieldName. array $attributes) Creates a select element populated with the (numerical) days of the month.. 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> . FormHelper::minute(string $fieldName. array('monthNames' => false)). you can supply the text as the final parameter as follows: echo $this->Form->day('created'). array $attributes) Creates a select element populated with the minutes of the hour. } General Purpose 433 . (Note: the default months are internationalized and can be translated using localization. the first option is ‘Day’). If a string. array $attributes) Creates a select element populated with ‘am’ and ‘pm’. Displaying and checking errors FormHelper::error(string $fieldName.

no label with class 'fancy' // has a label element same defaults echo $this->Form->input( 'username'. This change 434 Chapter 7. FormHelper::secure(array $fields = array()) Generates a hidden field with a security hash based on the fields used in the form. Changing the default options allows you to consolidate repeated options into a single method call: $this->Form->inputDefaults(array( 'label' => false. The $name parameter should be the entity name for the input: $this->Form->unlockField('User. Release 2. array('label' => 'Username') ). 2. FormHelper::unlockField($name) Unlocks a field making it exempt from the SecurityComponent field hashing.2. Core Libraries . All inputs created from that point forward will inherit the options declared in inputDefaults. You can declare a set of default options for input() using FormHelper::inputDefaults(). All methods now support a $attributes[’value’] key now which should be used in place of $selected. you should always close your forms using FormHelper::end(). As mentioned previously when using SecurityComponent. You can override the default options by declaring the option in the input() call: echo $this->Form->input('password'). This will ensure that the special _Token inputs are generated. you’ll automatically benefit from CSRF and form tampering features. 'div' => false. Otherwise it returns the validation message.CakePHP Cookbook Documentation. FormHelper::tagIsInvalid() Returns false if given form field described by the current entity has no errors. Working with SecurityComponent SecurityComponent offers several features that make your forms safer and more secure. This also allows the fields to be manipulated by JavaScript. By simply including the SecurityComponent in your controller. // No div. 'class' => 'fancy' ) ).id'). Setting Defaults for all fields New in version 2.0 updates $selected parameter removed The $selected parameter was removed from several methods in FormHelper. errors are rendered by default.x Note: When using FormHelper::input().

Don’t be afraid to use it often . faster.CakePHP Cookbook Documentation. This means that if there are validation errors on hidden fields. General Purpose 435 . the error-field class name will be applied. is now the current URL including passed. and querystring parameters.x simplifies the FormHelper methods. and more resilient to change. If you’re getting an error informing you that it isn’t there. and reduces the duplication that $selected created. array $settings = array()) The role of the HtmlHelper in CakePHP is to make HTML-related options easier. it’s usually due to its name being missing from a manually configured $helpers controller variable. that allow you to tack on any extra attributes on your tags. Many HtmlHelper methods include a $options parameter. This section will cover some of the methods of the HtmlHelper and how to use them. reducing the number of arguments. You can override this default by supplying $options[’url’] in the second parameter of $this->Form->create() FormHelper::hidden() Hidden fields no longer remove the class attribute. named. HtmlHelper class HtmlHelper(View $view. The effected methods are: • FormHelper::select() • FormHelper::dateTime() • FormHelper::year() • FormHelper::month() • FormHelper::day() • FormHelper::hour() • FormHelper::minute() • FormHelper::meridian() Default URLs on forms is the current action The default URL for all forms. and more flexible on where it is placed in relation to the root of a domain. Inserting Well-Formatted elements The most important task the HtmlHelper accomplishes is creating well formed markup. Using this helper will enable your application to be more light on its feet. Here are a few examples of how to use the $options parameter: Desired attributes: <tag class="someClass" /> Array parameter: array('class' => 'someClass') Desired attributes: <tag name="foo" value="bar" /> Array parameter: array('name' => 'foo'. 'value' => 'bar') Note: The HtmlHelper is available in all views by default. Release 2.you can cache views in CakePHP in order to save some CPU cycles when views are being rendered and delivered.

echo $this->Html->css(array('forms'. or an array with multiple files • $options (array) – An array of options or html attributes.encoding will be used.css" /> The first parameter can be an array to include multiple files. If null. Parameters • $path (mixed) – Either a string of the CSS file to link. charset=ISO-8859-1" /> HtmlHelper::css(mixed $path. If key ‘inline’ is set to false in $options parameter. Release 2. 'menu')). Will output: 436 Chapter 7. echo $this->Html->css('forms'). Will output: <meta http-equiv="Content-Type" content="text/html. Used to create a meta tag specifying the document’s character. charset=utf-8" /> Alternatively. Core Libraries . the value of App. Will output: <meta http-equiv="Content-Type" content="text/html.4. If key ‘rel’ in $options array is set to ‘import’ the stylesheet will be imported. This method of CSS inclusion assumes that the CSS file specified resides inside the /app/webroot/css directory if path doesn’t start with a ‘/’. By default it will append to the css block. echo $this->Html->charset('ISO-8859-1'). Creates a link(s) to a CSS style-sheet. You can use the block option to control which block the link element will be appended to.x HtmlHelper::charset($charset=null) Parameters • $charset (string) – Desired character set. 'tables'. Will output: <link rel="stylesheet" type="text/css" href="/css/forms.CakePHP Cookbook Documentation. Defaults to UTF-8 Example use: echo $this->Html->charset(). the link tags are added to the css block which you can print inside the head tag of the document. array $options = array()) Changed in version 2.

HtmlHelper::meta(string $type. Like css(). For example if you had a Blog plugin. This method is handy for linking to external resources like RSS/Atom feeds and favicons. either a string or a routing array. If you want to include a CSS file which shares a name with a loaded plugin you can do the following. Changed in version 2. Support for plugin syntax was added.css').x <link rel="stylesheet" type="text/css" href="/css/forms. • $url (mixed) – The URL for the meta tag. you would: Changed in version 2.css.ico'.css you could use the following: echo $this->Html->css('DebugKit.common. and also wanted to include app/webroot/css/Blog. • $options (array) – An array of html attributes. ?> // Output (line breaks added) <link href="http://example.toolbar. echo $this->Html->css('Blog.4.CakePHP Cookbook Documentation. string $url = null.ico'.array(’inline’ => false).css" /> You can include CSS files from any loaded plugin using plugin syntax. array('plugin' => false)).css" /> <link rel="stylesheet" type="text/css" href="/css/menu. array('type' => 'icon') ).1: The block option was added. array $options = array()) Parameters • $type (string) – The type meta tag you want. CakePHP contains a few shortcuts: type html rss atom icon translated value text/html application/rss+xml application/atom+xml image/x-icon <?php echo $this->Html->meta( 'favicon. ie .common. If you set the “type” attribute using the $options parameter.com/favicon.ico" type="image/x-icon" rel="alternate" /> <?php General Purpose 437 . Release 2. you can specify whether or not you’d like this tag to appear inline or appended to the meta block by setting the ‘inline’ key in the $options parameter to false.css'. '/favicon.ico" title="favicon.css" /> <link rel="stylesheet" type="text/css" href="/css/tables. To include app/Plugin/DebugKit/webroot/css/toolbar.

'content' => 'noindex')). 'enter any meta keyword here' ). array('type' => 'rss') ). Example: <?php echo $this->Html->meta( 'keywords'. ?> // Output <meta name="keywords" content="enter any meta keyword here" /> <?php echo $this->Html->meta( 'description'.rss'. Release 2. Returns a (X)HTML doctype tag. ?> // Output (line breaks added) <link href="http://example.1: The block option was added.rss" title="Comments" type="application/rss+xml" rel="alternate" /> This method can also be used to add the meta keywords and descriptions. To output a robots noindex tag use the following code: echo $this->Html->meta(array('name' => 'robots'. Changed in version 2. 'enter any meta description here' ).CakePHP Cookbook Documentation. Core Libraries . HtmlHelper::docType(string $type = ‘xhtml-strict’) Parameters • $type (string) – The type of doctype being made.x echo $this->Html->meta( 'Comments'.com/comments/index. Supply the doctype according to the following table: 438 Chapter 7. ?> // 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. '/comments/index.

Creates a formatted image tag. HtmlHelper::style(array $data.1: The default doctype is html5 in 2.0 Strict//EN" // "http://www. // Outputs: <!DOCTYPE html> echo $this->Html->docType('html4-trans'). Release 2.dtd"> Changed in version 2.org/TR/html4/loose. boolean $oneline = true) Parameters • $data (array) – A set of key => values with CSS properties. padding:10px. echo $this->Html->style(array( 'background' => '#633'.CakePHP Cookbook Documentation.1 echo $this->Html->docType().1.org/TR/xhtml1/DTD/xhtml1-strict.w3. // Outputs: // <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.dtd"> echo $this->Html->docType('html5'). General Purpose 439 . The path supplied should be relative to /app/webroot/img/. Especially handy if your CSS file is dynamic. • $options (array) – An array of html attributes. Will output: background:#633.01 Transitional//EN" // "http://www. HtmlHelper::image(string $path. 'padding' => '10px' )). // Outputs: // <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.x type html4-strict html4-trans html4-frame html5 xhtml-strict xhtml-trans xhtml-frame xhtml11 translated value HTML4 Strict HTML4 Transitional HTML4 Frameset HTML5 XHTML1 Strict XHTML1 Transitional XHTML1 Frameset XHTML1. border-bottom:1px solid #000. 'border-bottom' => '1px solid #000'. Builds CSS style definitions based on the keys and values of the array passed to the method. • $oneline (boolean) – Should the contents be on one line.w3. array $options = array()) Parameters • $path (string) – Path to the image.

jpg" alt="" /> You can include image files from any loaded plugin using plugin syntax.icon. • $url (mixed) – Either the string location. 'action' => 'view'. Support for plugin syntax was added. array( "alt" => "Brownies". If you want to include an image file which shares a name with a loaded plugin you can do the following.png.png" alt="CakePHP" /> To create an image link specify the link destination using the url option in $options.1: The fullBase option was added. array('alt' => 'CakePHP')).png'). 'url' => array('controller' => 'recipes'.png You could use the following: echo $this->Html->image('DebugKit.icon. array $options = array()) Parameters • $title (string) – The text to display as the body of the link. Core Libraries . To include app/Plugin/DebugKit/webroot/img/icon.jpg". Use $options to specify attributes for the element and whether or not the $title should be escaped. 440 Chapter 7. array('plugin' => false)).jpg" alt="Brownies" /> </a> If you are creating images in emails. 6) )). and also wanted to include app/webroot/img/Blog. General purpose method for creating HTML links. Release 2. HtmlHelper::link(string $title.CakePHP Cookbook Documentation.png'. or a routing array. array('fullBase' => true)). Will output: <a href="/recipes/view/6"> <img src="/img/recipes/6. or want absolute paths to images you can use the fullBase option: echo $this->Html->image("logo. Will output: <img src="/img/cake_logo. Changed in version 2. echo $this->Html->image("recipes/6.icon. you would: echo $this->Html->image('Blog.com/img/logo.x echo $this->Html->image('cake_logo. • $options (array) – An array of html attributes. For example if you had a Blog plugin. mixed $url = null. Will output: <img src="http://example.png'.png".

com/dashboards/index">Dashboard</a> Specify confirm key in $options to display a JavaScript confirm() dialog: echo $this->Html->link( 'Delete'."> Delete </a> Query strings can also be created with link(). 'full_base' => true ) ). array( 'controller' => 'images'.yourdomain. Release 2. 1. array('confirm' => 'Are you sure you wish to delete this recipe?') ). 'width' => 500)) ). Will output: <a href="http://www. '?' => array('height' => 400. Will output: <a href="/recipes/delete/6" onclick="return confirm( 'Are you sure you wish to delete this recipe?' ). 'target' => '_blank') ). array( 'controller' => 'dashboards'. array('controller' => 'recipes'. 'action' => 'delete'.x echo $this->Html->link( 'Enter'. Will output: General Purpose 441 . array('class' => 'button'. 'action' => 'index'. 'action' => 'view'.CakePHP Cookbook Documentation. echo $this->Html->link('View image'. Will output: <a href="/pages/home" class="button" target="_blank">Enter</a> Use ’full_base’ => true option for absolute URLs: echo $this->Html->link( 'Dashboard'. 6). '/pages/home'.

Core Libraries . array('alt' => 'Brownies')).howdy&quot. Release 2. "recipes/view/6". Using the string syntax for paramters (i. array( 'controller' => 'recipes'. array('escape' => false) ). array("alt" => "Brownies")). <?php echo $this->Html->link( $this->Html->image("recipes/6. To disable this conversion. <?php echo $this->Html->link( $this->Html->image('recipes/6. Will output: <a href="/recipes/view/id:6/comments:false"> <img src="/img/recipes/6. 'comments' => false ) ).jpg'.4 you can use the option escapeTitle to disable just escaping of title and not the attributes."> <img src="/img/recipes/6.CakePHP Cookbook Documentation. array('escapeTitle' => false. 'title' => 'hi "howdy"') ). 'id' => 6.jpg". 'recipes/view/6'. set the escape option to false in the $options array.jpg" alt="Brownies" /> </a> HTML special characters in $title will be converted to HTML entities. Will output: <a href="/recipes/view/6"> <img src="/img/recipes/6. <?php echo $this->Html->link( $this->Html->image("recipes/6. As of 2. “recipes/view/6/comments:false”) will result in the colon characters being HTML escaped and the link will not work as desired.x <a href="/images/view/1?height=400&width=500">View image</a> When using named parameters. use the array syntax and include names for ALL parameters in the URL.jpg".e. Will output: <a href="/recipes/view/6" title="hi &quot.jpg" alt="Brownies" /> </a> Setting escape to false will also disable escaping of attributes of the link.jpg" alt="Brownies" /> </a> 442 Chapter 7. 'action' => 'view'. array("alt" => "Brownies")).

Options: – type Type of media element to generate. ?> General Purpose 443 . – text Text to include inside the audio/video tag – pathPrefix Path prefix to use for relative URLs.mp3'). Release 2. and special options.ogg'.1. Changed in version 2. Use confirm key in $options instead. • $options (array) – Array of HTML attributes. codecs='theora. 'text' => 'Fallback text' )).mp4'.CakePHP Cookbook Documentation. Also check HtmlHelper::url method for more examples of different types of URLs. array('autoplay') ). relative to the webroot/{$options[’pathPrefix’]} directory. If type is not provided media type is guessed based on file’s mime type.mp4">Fallback text</video> <?php echo $this->Html->media( array( 'video.com/files/video. Or an array where each item itself can be a path string or an associate array containing keys src and type. array( 'fullBase' => true. 'type' => "video/ogg.6: The argument $confirmMessage was deprecated. array( 'src' => 'video.x Changed in version 2. array $options) Parameters • $path (string|array) – Path to the media file. valid values are “audio” or “video”. ?> // Output <video src="http://www. defaults to ‘files/’ – fullBase If set to true.4: The escapeTitle option was added. the src attribute will get a full address including domain name New in version 2.mp4'.somehost. HtmlHelper::media(string|array $path. vorbis'" ) ).mp3"></audio> <?php echo $this->Html->media('video. Returns a formatted audio/video tag: <?php echo $this->Html->media('audio. ?> // Output <audio src="/files/audio.

mp4" type="video/mp4"/> <source src="/files/video. Returns text wrapped in a specified tag. string $text. ?> // Output <span class="welcome">Hello World</span> // No text specified. ?> // Output <span class="welcome"> Note: Text is not escaped by default but you may use $options[’escape’] = true to escape your text.: 444 Chapter 7. • $options (array) – An array of html attributes. <?php echo $this->Html->tag('span'. array $options) Parameters • $class (string) – The class name for the div. array $options) Parameters • $tag (string) – The tag name being generated. If no text is specified. only an opening div tag is returned. HtmlHelper::div(string $class. null. • $text (string) – The content inside the div. If the ‘escape’ key has been set to true in the last parameter.CakePHP Cookbook Documentation.: <?php echo $this->Html->tag('span'. array('class' => 'welcome')). codecs='theora. This replaces a fourth parameter boolean $escape = false that was available in previous versions. • $options (array) – An array of html attributes. Used for creating div-wrapped sections of markup.x // Output <video autoplay="autoplay"> <source src="/files/video. and the second is used to supply the text to be wrapped by div tags. Core Libraries . The first parameter specifies a CSS class. 'Hello World. string $text.'.ogg" type="video/ogg. $text will be printed HTML-escaped. vorbis'"/> </video> HtmlHelper::tag(string $tag. array('class' => 'welcome')). • $text (string) – The contents for the tag. Release 2. If no text is specified then only the opening <tag> is returned.

'Hello World. If you wish to override which block name is used. • $options (array) – An array of html attributes. or an array of strings for multiple files.: <?php echo $this->Html->para(null. Will output: General Purpose 445 . only a starting <p> tag is returned. By default. the script tags will instead be added to the script block which you can print elsewhere in the document. This defaults to true. If you override this by setting $options[’inline’] to false. array $options) Parameters • $class (string) – The class name for the paragraph. mixed $options) Parameters • $url (mixed) – Either a string to a single JavaScript file. If no text is supplied. Include a script file(s). ?> // Output <p>Hello World. This method of JavaScript file inclusion assumes that the JavaScript file specified resides inside the /app/webroot/js directory: echo $this->Html->script('scripts'). script tags are added to the document inline. • $text (string) – The content inside the paragraph. Returns a text wrapped in a CSS-classed <p> tag. ?> // Output <div class="error">Please enter your credit card number. Release 2. contained either locally or as a remote URL. $options[’once’] controls whether or not you want to include this script once per request or more than once. 'Please enter your credit card number.</div> HtmlHelper::para(string $class.').CakePHP Cookbook Documentation.</p> HtmlHelper::script(mixed $url.x <?php echo $this->Html->div('error'. If an array of script tags is used. • $options (array) – An array of html attributes. you can do so by setting $options[’block’]. the attributes will be applied to all of the generated script tags. string $text.'). You can use $options to set additional properties to the generated script tag.

plugins.js"></script> You can append the script tag to a specific block using the block option: echo $this->Html->script('wysiwyg'. $options = array()) Parameters • $code (string) – The code to go in the script tag.js'.com/jquery.js').js'). You can also link to a remote URL: echo $this->Html->script('http://code.js you could use the following: echo $this->Html->script('DebugKit.toolbar.js"></script> You can link to files with absolute paths as well to link files that are not in app/webroot/js: echo $this->Html->script('/otherdir/script_file'). Core Libraries .x <script type="text/javascript" href="/js/scripts.CakePHP Cookbook Documentation. 'wysiwyg'. In your layout you can output all the script tags added to ‘scriptBottom’: echo $this->fetch('scriptBottom'). HtmlHelper::scriptBlock($code. If you want to include a script file which shares a name with a loaded plugin you can do the following. You can include script files from any loaded plugin using plugin syntax.min. Support for plugin syntax was added. and also wanted to include app/webroot/js/Blog.1: The block option was added. Generate a code block containing $code. Other options defined will be added as attributes 446 Chapter 7. array('block' => 'scriptBottom')).com/jquery. echo $this->Html->script(array('jquery'.min. For example if you had a Blog plugin.js"></script> <script type="text/javascript" href="/js/scripts. array('plugin' => false)). To include app/Plugin/DebugKit/webroot/js/toolbar. Set $options[’inline’] to false to have the script block appear in the script view block. 'scripts')).jquery.js. Will output: <script type="text/javascript" href="http://code. you would: echo $this->Html->script('Blog. • $options (array) – An array of html attributes.plugins. Release 2.js"></script> <script type="text/javascript" href="/js/wysiwyg.js"> </script> The first parameter can be an array to include multiple files. Will output: <script type="text/javascript" href="/js/jquery. Changed in version 2.jquery.

Build a nested list (UL/OL) out of an associative array: $list = array( 'Languages' => array( 'English' => array( 'American'. array $itemOptions = array(). Output: // Output (minus the whitespace) <ul> General Purpose 447 . • $itemOptions (array) – Additional HTML attributes of the list item (LI) tag. 'British'. • $options (array) – Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag. Release 2. $this->Html->scriptEnd(). HtmlHelper::scriptStart($options = array()) Parameters • $options (array) – An array of html attributes to be used when scriptEnd is called. echo $this->Js->alert('I am in the javascript'). echo $this->Html->nestedList($list). ). array $options = array(). array(’defer’ => true)). ) ). 'Spanish'.x to script tags. • $tag (string) – Type of list tag to use (ol/ul). $this->Html->scriptBlock(’stuff’. HtmlHelper::nestedList(array $list. will create a script tag with defer="defer" attribute. Options are the same as scriptBlock() HtmlHelper::scriptEnd() End a buffering script block. returns the generated script element or null if the script block was opened with inline = false. 'German'. An example of using scriptStart() and scriptEnd() would be: $this->Html->scriptStart(array('inline' => false)). This code block will capture all output between scriptStart() and scriptEnd() and create an script tag. string $tag = ‘ul’) Parameters • $list (array) – Set of elements to list. 'Canadian'. Begin a buffering code block.CakePHP Cookbook Documentation.

'Active')).2 you can set attributes per column. 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> Changed in version 2. array('class' => 'status'). array $thOptions = null) Parameters • $names (array) – An array of strings to create table headings.'Title'. Output: <tr> <th>Date</th> <th>Title</th> <th>Active</th> </tr> echo $this->Html->tableHeaders( array('Date'. Core Libraries .'Active').CakePHP Cookbook Documentation. • $trOptions (array) – An array of html attributes for the <tr> • $thOptions (array) – An array of html attributes for the <th> elements Creates a row of table header cells to be placed inside of <table> tags. these are used instead of the defaults provided in the $thOptions: 448 Chapter 7. Release 2. As of 2. echo $this->Html->tableHeaders(array('Date'.2: tableHeaders() now accepts attributes per cell. see below. array $trOptions = null.x <li>Languages <ul> <li>English <ul> <li>American</li> <li>Canadian</li> <li>British</li> </ul> </li> <li>Spanish</li> <li>German</li> </ul> </li> </ul> HtmlHelper::tableHeaders(array $names. 'Title'.

2007</td><td>Best Brownies</td><td>Yes</td></tr> <tr><td>Jun 21st. array( 'Aug 1st. • $evenTrOptions (array) – An array of html attributes for the even <tr>’s. assigning <tr> attributes differently for odd. array('Name' => array('class' => 'highlight')). 'Yes').and even-numbered rows. 2007'. $useCount = false. in rows. array('Jun 21st. 'Yes'). 2007</td><td>Smart Cookies</td><td>Yes</td></tr> <tr><td>Aug 1st. 2006'. 'Smart Cookies'. 2007'. Output: <tr><td>Jul 7th. Release 2.CakePHP Cookbook Documentation. General Purpose 449 . Output: <tr> <th>id</th> <th class="highlight">Name</th> <th class="sortable">Date</th> </tr> HtmlHelper::tableCells(array $data. 'Yes'). array('Aug 1st. 'No'). array $oddTrOptions = null. )). • $oddTrOptions (array) – An array of html attributes for the odd <tr>’s. $continueOddEven = true) Parameters • $data (array) – A two dimensional array with data for the rows. 'Smart Cookies'. 2007'. • $useCount (boolean) – Adds class “column-$i”. array('Date' => array('class' => 'sortable')) )). will use a non-static $count variable. Creates table cells. 'Best Brownies'. 'Anti-Java Cake'. 2007'. so that the odd/even count is reset to zero just for that call. 2006</td><td>Anti-Java Cake</td><td>No</td></tr> echo $this->Html->tableCells(array( array( 'Jul 7th. echo $this->Html->tableCells(array( array('Jul 7th. array $evenTrOptions = null. array('Jun 21st. • $continueOddEven (boolean) – If false. array( 'Best Brownies'. 'Yes').x echo $this->Html->tableHeaders(array( 'id'. array('class' => 'highlight') ). Wrap a single table cell within an array() for specific <td>-attributes. 2006'.

array('Yellow'. 'Orange'). ). Output: 450 Chapter 7. 'Banana'). Core Libraries .x 'Anti-Java Cake'. 2007 </td> <td> Smart Cookies </td> <td> Yes </td> </tr> <tr> <td> Aug 1st. array('Orange'. array('No'. Output: <tr> <td> Jul 7th. 2006 </td> <td> Anti-Java Cake </td> <td id="special"> No </td> </tr> echo $this->Html->tableCells( array( array('Red'. 'Apple').CakePHP Cookbook Documentation. 2007 </td> <td class="highlight"> Best Brownies </td> <td> Yes </td> </tr> <tr> <td> Jun 21st. array('class' => 'darker') ). Release 2. )). array('id' => 'special')) ).

// Output /posts/list. "ext" => "rss" )). "action" => "list". // Output /posts/view/bar Here are a few more usage examples: URL with named parameters: echo $this->Html->url(array( "controller" => "posts". the full base URL will be prepended to the result: echo $this->Html->url(array( "controller" => "posts". // Output /posts/view/foo:bar URL with extension: echo $this->Html->url(array( "controller" => "posts". If $url is empty.CakePHP Cookbook Documentation.x <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> HtmlHelper::url(mixed $url = NULL. it returns the REQUEST_URI. true). "action" => "view".rss URL (starting with ‘/’) with the full base URL prepended: echo $this->Html->url('/posts'. otherwise it generates the URL for the controller and action combo. Release 2. If full is true. "bar" )). • $full (mixed) – Either a boolean to indicate whether or not the base path should be included or an array of options for Router::url() Returns a URL pointing to a combination of controller and action. General Purpose 451 . "action" => "view". "foo" => "bar" )). boolean $full = false) Parameters • $url (mixed) – A routing array.

. )).x // Output http://somedomain. // Output /posts/search?foo=bar#first For further information check Router::url5 in the API. Release 2. 'http://example.cakephp. 'javascriptlink' => '<script src="%s"%s></script>'. "action" => "search".com/posts URL with GET params and named anchor: echo $this->Html->url(array( "controller" => "posts". 'javascriptstart' => '<script>'.CakePHP Cookbook Documentation. "?" => array("foo" => "bar").php containing: $config = array('tags' => array( 'css' => '<link rel="%s" href="%s" %s>'. Creating breadcrumb trails with HtmlHelper 5 http://api. You can then load this tag set by calling $this->Html->loadConfig(’html5_tags’).html#_url 452 Chapter 7.. however if you need to generate HTML for HTML5 you will need to create and load a new tags config file containing the tags you’d like to use. HtmlHelper::useTag(string $tag) Returns a formatted existent block of $tag: $this->Html->useTag( 'form'. 'style' => '<style%s>%s</style>'.org/2. Core Libraries . 'class' => 'myform') ). 'charset' => '<meta charset="%s">'.com'. 'javascriptblock' => '<script%s>%s</script>'.8/class-Router. "#" => "first" )). // . string $path = null) The built-in tag sets for HtmlHelper are XHTML compliant. To change the tags used create app/Config/html5_tags.com" method="post" class="myform"> Changing the tags output by HtmlHelper HtmlHelper::loadConfig(mixed $configFile. array('method' => 'post'. Output: <form action="http://example.

Release 2. mixed $options = null) Now. Changed in version 2.’. We recommend using regular JavaScript and directly interacting with JavaScript libraries where possible. HtmlHelper::getCrumbList(array $options = array(). To set this up. 'escape' => false )). HtmlHelper::addCrumb(string $name. • $startText (string|array) – The text or element that precedes the ul. The $startText option can also accept an array. $this->Html->addCrumb('Add User'. in your view you’ll want to add the following to start the breadcrumb trails on each of the pages: $this->Html->addCrumb('Users'. array( 'text' => $this->Html->image('home.x HtmlHelper::getCrumbs(string $separator = ‘&raquo. This option works the same as the $startText option for getCrumbs(). Changed in version 2. 'action' => 'add')).5: The ‘escape’ option was added. mixed $startText) Parameters • $options (array) – An array of html attributes for the containing <ul> element.3: The ‘separator’. This is useful when you always want to include a root link. General Purpose 453 . ‘lastClass’ and ‘escape’ options.png'). first add something similar to the following in your layout template: echo $this->Html->getCrumbs(' > '. You can use the $startText parameter to provide the first breadcrumb link/text.CakePHP Cookbook Documentation. 'home'). JsHelper class JsHelper(View $view. 'Home'). array $settings = array()) Warning: The JsHelper is currently deprecated and completely removed in 3. This method uses HtmlHelper::tag() to generate list and its elements. Any keys that are not text or url will be passed to link() as the $options parameter. ‘firstClass’. '/users'). string $link = null. Works similar to getCrumbs(). array('controller' => 'users'. Returns breadcrumbs as a (x)html list. 'url' => array('controller' => 'pages'. Can also contain the ‘separator’.x.1: The $startText parameter now accepts an array. This will add the output of “Home > Users > Add User” in your layout where getCrumbs was added. ‘firstClass’ and ‘lastClass’ options were added.1: The $startText parameter was added. This gives more control over the generated first link: echo $this->Html->getCrumbs(' > '. so it uses options which every crumb was added with. 'action' => 'display'. Changed in version 2. string|array|bool $startText = false) CakePHP has the built-in ability to automatically create a breadcrumb trail in your app. Changed in version 2.

To do this at the end of each page. To include it in all pages. JavaScript engine selection is declared when you include the helper in your controller: public $helpers = array('Js' => array('Jquery')). add this line to the <head> section of app/View/Layouts/default. // Include jQuery library Replace jquery with the name of your library file (. there is one caveat: By default. // Write cached scripts Warning: You must include the library in your page and print the cache for the helper to function. JavaScript Engines form the backbone of the new JsHelper. As mentioned before.ctp: echo $this->Html->script('jquery'). By default scripts are cached. but we encourage the community to expand the library compatibility. A JavaScript engine translates an abstract JavaScript element into concrete JavaScript code specific to the JavaScript library being used. While the API is not as expansive as the previous AjaxHelper we feel that the adapter based solution allows for a more extensible solution giving developers the power and flexibility they need to address their specific application needs. Core Libraries . and you must explicitly print out the cache. array('inline' => false) ).js will be added to the name). In addition they create an extensible system for others to use. // Tell jQuery to go into noconflict mode 454 Chapter 7. Rather than drop Prototype in favour of another JavaScript library. Using jQuery with other libraries The jQuery library. We created an Adapter based helper. the jQuery engine will be used as the default. “global” objects are stored inside the jQuery namespace as well. If you do not declare a specific engine. echo $this->Html->scriptBlock( 'var $j = jQuery.CakePHP Cookbook Documentation. and jQuery/jQuery UI. While we still think these are excellent JavaScript libraries. and virtually all of its plugins are constrained within the jQuery namespace. jQuery uses “$” as a shortcut for “jQuery” To override the “$” shortcut. use the jQueryObject variable: $this->Js->JqueryEngine->jQueryObject = '$j'. The above would use the Jquery Engine in the instances of JsHelper in your views. or YUI). That said. Mootools/Mootools-more. As a general rule. and included 3 of the most requested libraries. there are three engines implemented in the core. the community has been asking for support for other libraries. Release 2. MooTools. so you shouldn’t get a clash between jQuery and any other library (like Prototype. include this line just before the ending </body> tag: echo $this->Js->writeBuffer(). Using a specific JavaScript engine First of all download your preferred JavaScript library and place it in app/webroot/js Then you must include the library in your page.x Since the beginning CakePHP’s support for JavaScript has been with Prototype/Scriptaculous.'. Prototype/Scriptaculous.noConflict().

this will return the buffer contents in a script tag. If you are willing to use an other JavaScript engine than the default. with a few additional restrictions. Be sure to declare the JsHelper and its engine on top of the $helpers array in your The selected JavaScript engine may disappear (replaced by the default) from the JsHelper object in your helper. You should not directly access the Engine helper except in rare occasions. Method chaining allows you to write shorter. General Purpose 455 . $eventCode). $this->Js->event('click'. (method chaining only works in PHP5). They must have the Engine suffix. elements and layout. JavaScript engine usage The JsHelper provides a few methods. 'CustomHelper' ). The JsHelper by default buffers almost all script code generated. they should extend JsBaseEngineHelper in order to leverage the most of the new API. do the helper setup in your controller as follows: public $helpers = array( 'Js' => array('Prototype'). allowing you to collect scripts throughout the view. Is an example of method chaining. more expressive code: $this->Js->get('#foo')->event('click'. Doing that will have no effect.x Using the JsHelper inside customHelpers Declare the JsHelper in the $helpers array in your customHelper: public $helpers = array('Js'). if you miss to do so and you will get code that does not fit your JavaScript library. and acts as a facade for the the Engine helper. and output it in one place. DojoHelper is not good. $eventCode). Furthermore. Release 2. Creating a JavaScript Engine JavaScript engine helpers follow normal helper conventions. Outputting buffered scripts is done with $this->Js->writeBuffer().CakePHP Cookbook Documentation. Note: It is not possible to declare a JavaScript engine inside a custom helper. Method chaining is not possible in PHP4 and the above sample would be written like: $this->Js->get('#foo'). DojoEngineHelper is correct. $this->Js->get() returns a $this. You can disable buffering wholesale with the $bufferScripts property or setting buffer => false in methods taking $options. allowing you to chain the methods using the selection. Using the facade features of the JsHelper allows you to leverage the buffering and method chaining features built-in. Warning: controller. Since most methods in JavaScript begin with a selection of elements in the DOM.

if an inline block is generated should it be wrapped in <![CDATA[ . If you are not planning on switching JavaScript libraries. The new JsHelper if used correctly avoids both of those issues. Core Libraries .wrap cached scripts in domready event (default true) • safe ..x Common options In attempts to simplify development where JavaScript libraries can change.Set to false to prevent script cache from being cleared (default true) • onDomReady .Set to true to have scripts output as a script block inline if cache is also true. Callback wrapping By default all callback options are wrapped with the an anonymous function with the correct arguments. a script link tag will be generated. Options • inline . (default true) • cache . Working with buffered scripts One drawback to previous implementation of ‘Ajax’ type features was the scattering of script tags throughout your document. JsHelper::buffer($content) Add $content to the internal script buffer. and the inability to buffer scripts added by elements in the layout. these common options will be mapped out to the library specific options internally. each library also supports all of its native callbacks and options.Set to true to have scripts cached to a file and linked in (default false) • clear . This will allow all scripts generated in layout elements to be output in one place. It is recommended that you place $this->Js->writeBuffer() at the bottom of your layout file above the </body> tag.. Pass in false to not clear the buffer at the same time. It should be noted that buffered scripts are handled separately from included script files.CakePHP Cookbook Documentation. a common set of options is supported by JsHelper. ]]> (default true) Creating a cache file with writeBuffer() requires that webroot/js be world writable and allows a browser to cache generated script resources for any page. Buffering methods that are not normally buffered Some methods in the helpers are buffered by default. JsHelper::writeBuffer($options = array()) Writes all JavaScript generated so far to a code block or caches them to a file and returns a linked script. JsHelper::getBuffer($clear = true) Get the contents of the current buffer. You can disable this behavior by supplying the wrapCallbacks = false in your options array. The engines buffer the following methods by default: • event • sortable • drag • drop 456 Chapter 7. Release 2.

Release 2.Whether or not to use an effect to move sortable into final position. Whenever you see separate lists for Options and Event Options both sets of parameters are supplied in the $options array for the method. Event Options •start . •revert .String prepended to the returned data. false).Distance a sortable must be dragged before sorting starts. 'alert("whoa!"). For example the each() method does not normally buffer: $this->Js->each('alert("whoa!"). there is also a subset of common options that are translated into library specific options. This method is a proxy for json_encode() with a few extra features added via the $options parameter. $options = array()) Serializes $data into JSON. •postfix .Container for move action •handle .Event fired during sorting General Purpose 457 .Event fired when sorting starts •sort . This is done to provide end developers with as unified an API as possible. you can pass a false in as the last argument: $this->Js->event('click'. By appending an boolean to the end of the arguments you can force other methods to go into the buffer. Other Methods The core JavaScript Engines provide the same feature set across all libraries. The above would force the each() method to use the buffer.String appended to the returned data. Options: •prefix . The normalized options are: Options •containment . The following list of methods are supported by all the Engines included in the CakePHP core.CakePHP Cookbook Documentation.Opacity of the placeholder •distance . This would force the event function which normally buffers to return its result. Example Use: $json = $this->Js->object($data).Selector to handle element.x • slider Additionally you can force any other method in JsHelper to use the buffering. true). Conversely if you want a method that does buffer to not buffer. Only this element will start sort action. JsHelper::object($data. •opacity .'.'. JsHelper::sortable($options = array()) Sortable generates a JavaScript snippet to make a set of elements (usually a list) drag and drop sortable.

Release 2. •evalScripts . •data . 'sort' => 'onSort'. •before . Example Use: $this->Js->get('#my-list').Callback to fire on success. •error . $options = array()) Generate a JavaScript snippet to create an XmlHttpRequest or ‘AJAX’ request.sortable({ containment:"parent". Other options are supported by each JavaScript library. you would get the following code in your generated JavaScript block $("#myList").Additional data to send. 458 Chapter 7. start:onStart.CakePHP Cookbook Documentation. •dataExpression .x •complete . 'wrapCallbacks' => false )). Default is html for most libraries.Should the data key be treated as a callback.Data type for response. •type . JsHelper::request($url. stop:onStop }). sort:onSort.Dom id to update with the content of the response. distance:5. ‘json’ and ‘html’ are supported. Assuming you were using the jQuery engine.Whether or not <script> tags should be eval’ed.Callback to fire on request failure. Useful for supplying $options[’data’] as another JavaScript expression. Event Options •complete . 'containment' => 'parent'. 'start' => 'onStart'.Callback to fire on request initialization. 'complete' => 'onStop'.The method to make the request with defaults to GET in more libraries •async . •update . and you should check the documentation for your JavaScript library for more detailed information on its options and parameters. $this->Js->sortable(array( 'distance' => 5.Whether or not you want an asynchronous request. Options •method .Event fired when sorting completes. Core Libraries . •success .Callback to fire on complete.

call get() again with a new element. mixed $two = null) Pass variables into JavaScript. To change the active selection. 'wrapCallbacks' => false )). 10). 'start' => 'onStart'. Event Options •start . The JsHelper now will reference all other element based methods on the selection of #element. 'update' => '#element') ) ). The JavaScript variable used to output set variables can be controlled with JsHelper::$setVariable. Release 2.The element that acts as a bounding box for the draggable element.Event fired when dragging stops (mouse release) Example use: $this->Js->get('#element').Event fired on every step of the drag •stop . 'param1'). y) •container . an array(x.Event fired when the drag starts •drag . Options •handle .selector to the handle element. $this->Js->request( array('action' => 'foo'. Allows you to set variables that will be output when the buffer is fetched with JsHelper::getBuffer() or JsHelper::writeBuffer().The pixel grid that movement snaps to. If you were using the jQuery engine the following code would be added to the buffer General Purpose 459 . $this->Js->drag(array( 'container' => '#content'. 'drag' => 'onDrag'. array('async' => true. JsHelper::get($selector) Set the internal ‘selection’ to a CSS selector.x Example use: $this->Js->event( 'click'. 'stop' => 'onStop'. JsHelper::set(mixed $one. 'snapGrid' => array(10. The active selection is used in subsequent operations until a new selection is made: $this->Js->get('#element'). •snapGrid .CakePHP Cookbook Documentation. JsHelper::drag($options = array()) Make an element draggable.

Class to add to droppable when a draggable is over. If you were using the jQuery engine the following code would be added to the buffer $("#element").items".Event fired when a drag is removed from a drop zone without being dropped.10]. 'leave' => 'onExit'. start:onStart. See your libraries implementation for additional usage and features. Event Options •drop . stop:onStop }). Mootools droppables inherit all options from Drag.Selector for elements this droppable will accept. Example use: $this->Js->get('#element').Event fired when a drag enters a drop zone.Event fired when an element is dropped into the drop zone. 'drop' => 'onDrop'. Droppables are implemented as an extension of Drag. grid:[10. over:onHover }).CakePHP Cookbook Documentation. out:onExit. Note: Droppables in Mootools function differently from other libraries. So in addition to making a get() selection for the droppable element. Options 460 Chapter 7. Release 2. You must also provide a selector rule to the draggable element. •leave . •hover . JsHelper::slider($options = array()) Create snippet of JavaScript that converts an element into a slider ui widget.draggable({ containment:"#content". drop:onDrop.droppable({ accept:".x $("#element"). Options •accept . 'hover' => 'onHover'. Core Libraries . 'wrapCallbacks' => false )). $this->Js->drop(array( 'accept' => '.items'. JsHelper::drop($options = array()) Make an element accept draggable elements and act as a dropzone for dragged elements. •hoverclass . drag:onDrag. Furthermore.

Fired when the slider’s value is updated •complete . •slideIn . •hide . Release 2. General Purpose 461 . $this->Js->slider(array( 'complete' => 'onComplete'.x •handle .Slide an element in. Supported effect names The following effects are supported by all JsEngines •show .The number of steps or ticks the slider will have.CakePHP Cookbook Documentation. 'wrapCallbacks' => false )). stop:onComplete. If you were using the jQuery engine the following code would be added to the buffer $("#element").hide an element. value:2 }). •value .slider({ change:onChange.The max value for the slider. 'max' => 10.Fired when the user stops sliding the handle Example use: $this->Js->get('#element'). •fadeOut .The id of the element used in sliding.The min value for the slider.The direction of the slider either ‘vertical’ or ‘horizontal’ •min . •max . orientation:"vertical". min:0. 'value' => 2. •fadeIn . •direction . By default this method is not buffered and returns its result.The initial offset of the slider.reveal an element. max:10. •step . 'change' => 'onChange'. JsHelper::effect($name.Fade out an element. $options = array()) Creates a basic effect. Events •change . 'min' => 0. 'direction' => 'vertical'.Fade in an element.

} unless disabled with the $options. Release 2. $result = $this->Js->effect('fadeIn'). $this->Js->alert('hey you!'). by passing setting the stop option to false: $this->Js->get('#some-link').. Options •wrap . Callbacks will be wrapped with function (event) { .x •slideOut . 462 Chapter 7. function (event) { alert('hey you!'). $options = array()) Bind an event to the current selection. }). $content.CakePHP Cookbook Documentation. Note that the default browser event is not cancelled: $('#some-link'). ‘fast’.Whether you want the event to stop.Slide an element out.. (defaults to true) •stop . JsHelper::event($type. $this->Js->alert('hey you!')). Example use If you were using the jQuery engine: $this->Js->get('#element').Speed at which the animation should occur.bind('click'. function (event) { alert('hey you!'). // $result contains $("#foo").bind('click'. array('stop' => false) ). $this->Js->event( 'click'. If you were using the jQuery library you would get the following JavaScript code: $('#some-link'). $content should contain the function body for the callback. Options •speed . Core Libraries .Whether you want the callback wrapped in an anonymous function. }). return false. If you were using the jQuery library you would the following JavaScript code would be added to the buffer. Not all effects use the speed option. You can remove the return false.fadeIn(). $type can be any of the normal DOM events or a custom event type if your library supports them. $this->Js->event('click'. Accepted values are ‘slow’. (defaults to true) Example use: $this->Js->get('#some-link').

x JsHelper::domReady($callback) Creates the special ‘DOM ready’ event. and inserts $callback. confirm does not buffer.message'). $default) Create a JavaScript snippet containing a prompt() snippet. $alert = $this->Js->alert('Hey there').Confirm message displayed before sending the request.The URL you wish the XHR request to submit to. JsHelper::confirm($message) Create a JavaScript snippet containing a confirm() snippet. JsHelper::submit($caption = null. alert does not buffer. Options •url . Using confirm. Example use: General Purpose 463 . prompt does not buffer. 'blue'). By default. •buffer . does not replace any before callback methods in the generated XmlHttpRequest.CakePHP Cookbook Documentation. and returns the script snippet. •confirm . JsHelper::prompt($message. By default. and returns the script snippet. JsHelper::alert($message) Create a JavaScript snippet containing an alert() snippet. $options = array()) Create a submit input button that enables XmlHttpRequest submitted forms. or other more specialized setups that are beyond the scope of this helper.'). •wrapCallbacks . $prompt = $this->Js->prompt('What is your favorite color?'.css({color: "red"}). JsBaseEngine::event(). Options can include both those for FormHelper::submit() and JsBaseEngine::request(). Release 2. Files do not transfer over XmlHttpRequest and require an iframe. By default. $this->Js->each('$(this). JsHelper::each($callback) Create a snippet that iterates over the currently selected elements. Using the jQuery engine would create the following JavaScript: $('div. }).message').each(function () { $(this). Example: $this->Js->get('div. and returns the script snippet. cannot send files. $alert = $this->Js->confirm('Are you sure?'). Forms submitting with this method.Set to false to disable automatic callback wrapping. JsHelper::writeBuffer() automatically wraps the buffered scripts in a domReady method.css({color: "red"}).Disable the buffering and return a script tag in addition to the link.

•id . array( 'update' => '#content'. array('page' => 2). Pass true for $isForm if the current selection is a form 464 Chapter 7. You can use the htmlAttributes option to add in additional custom attributes. echo $this->Js->link('Page 2'. Will create a link pointing to /page:2 and updating #content with the response. echo $this->Js->submit('Save'.CakePHP Cookbook Documentation.Generate a confirm() dialog before sending the event. Standard attributes are class. Will create a submit button with an attached onclick event. JsHelper::event(). both FormHelper::submit() and JsHelper::link($title. escape. 'type' => 'json'. Example use: echo $this->Js->link( 'Page 2'. Outputs the following HTML: <a href="/posts/index/page:2" other="value">Page 2</a> JsHelper::serializeForm($options = array()) Serialize the form attached to $selector. $options is a html attributes array that are appended to the generated anchor element.use a custom id. The click event will be buffered by default.x echo $this->Js->submit('Save'. If an option is not part of the standard attributes or $htmlAttributes it will be passed to JsHelper::request() as an option. $url = null.Disable the buffering and return a script tag in addition to the link. Release 2. onblur and onfocus. Options •confirm . array('update' => '#content')). array('update' => '#content') ). Shows how you can combine options that JsHelper::request() when using submit. Options can include both those for HtmlHelper::link() and JsHelper::request(). 'async' => false )). •htmlAttributes . If an id is not supplied. id. 'htmlAttributes' => array('other' => 'value') )). •buffer . $options = array()) Create an HTML anchor element that has a click event bound to it. a randomly generated one will be created for each link generated. rel.additional non-standard htmlAttributes. array( 'update' => '#content'. array('page' => 2). 'div' => false. Core Libraries . title.

2 you need to tell the PaginatorHelper that you want to make JavaScript enhanced links instead of plain HTML ones. AJAX Pagination Much like AJAX Pagination in 1. To do so. Release 2. you can use the JsHelper to handle the creation of AJAX pagination links instead of plain HTML links. Similar to 1. or an input? (defaults to false) •inline .is the rendered statement going to be used inside another JS statement? (defaults to false) Setting inline == false allows you to remove the trailing .. Of course this element must exist.CakePHP Cookbook Documentation. or use the serialize method in an Object literal. The PaginatorHelper now knows to make JavaScript enhanced links. You also should set evalScripts to true if you are using the Mootools or Prototype adapters. 'evalScripts' => true )). This is useful when you need to serialize a form element as part of another JavaScript operation. By default the JsHelper uses jQuery. Converts the form or the form element attached to the current selection into a string/json object (depending on the library implementation) for use with XHR operations. Escapes any string values into JSON compatible strings.location. The indicator option is not supported by JsHelper and will be ignored. and that those links should update the #content element. call the options() at the top of your view: $this->Paginator->options(array( 'update' => '#content'. Next link in the JavaScript library you want to use. JsHelper::value($value) Converts a PHP-native variable of any type to a JSON-equivalent representation. public $helpers = array('Js'). UTF-8 characters will be escaped. Making AJAX Links Before you can create AJAX links you must include the JavaScript library that matches the adapter you are using with JsHelper. Also make sure to include RequestHandlerComponent in your components.2. Options •isForm . For this example we’ll be using jQuery: echo $this->Html->script('jquery'). without evalScripts these libraries will not be able to chain requests together. Add the following to your controller: public $components = array('RequestHandler'). So in your layout include jQuery (or whichever library you are using).is the current selection a form. Since the JsHelper automatically buffers all generated script content to reduce the number of <script> tags in your source code you must General Purpose 465 . You then create all the links as needed for your pagination features. and often times you want to wrap $content_for_layout with a div matching the id used for the update option. JsHelper::redirect($url) Redirect the page to $url using window.x element.

we’ve included an indicator image file. At the bottom of your view file. you must add any indicator effects yourself: <!DOCTYPE html> <html> <head> <?php echo $this->Html->script('jquery'). array('buffer' => false) ). that will display a busy indicator animation that we will show and hide with the JsHelper. the new features offered by JsHelper allow for more control and more complex effects to be created.gif'. </head> <body> <div id="content"> <?php echo $this->fetch('content'). This will show/hide the busy-indicator element before and after the #content div is updated. Core Libraries . ?> //more stuff here. Adding effects and transitions Since indicator is no longer supported. 'complete' => $this->Js->get('#busy-indicator')->effect( 'fadeOut'. so you don’t have worry about the same JavaScript being output twice. array('id' => 'busy-indicator') ). When you write the buffer. Be sure to include: echo $this->Js->writeBuffer(). it is also cleared. With the above layout. To do that we need to update our options() function: $this->Paginator->options(array( 'update' => '#content'. You may see a situation where the indicator. ?> </div> <?php echo $this->Html->image( 'indicator. )).gif file inside app/webroot/img folder. Release 2. ?> </body> </html> Remember to place the indicator. 'before' => $this->Js->get('#busy-indicator')->effect( 'fadeIn'. 'evalScripts' => true. Although indicator has been removed. array('buffer' => false) ). } in your main CSS file. You need to put in this CSS #busy-indicator { display:none.CakePHP Cookbook Documentation.gif displays immediately upon the page load. 466 Chapter 7.x write the buffer out. If you omit this you will not be able to chain AJAX pagination links.

. The second parameter is used to choose a predefined currency formatting scheme: $currency EUR GBP USD 1234. They do not automatically echo the output into the view. Changed in version 2.56. All of these functions return the formatted number. $number. The following options are available: General Purpose 467 . should be a floating point number that represents the amount of money you are expressing.56 The third parameter is an array of options for further defining the output. This method is used to display a number in common currency formats (EUR. format numbers to specific precisions and also to give you more flexibility with formatting numbers. $currency).56 £1. string $currency = ‘USD’. $currency). see below.GBP. The first parameter.234.234. • $options (array) – Options. array $options = array()) Parameters • $number (float) – The value to covert.1: NumberHelper have been refactored into CakeNumber class to allow easier use outside of the View layer.x NumberHelper class NumberHelper(View $view. NumberHelper::currency(float $number. formatted by currency type C1. these methods are accessible via the NumberHelper class and you can call it as you would call a normal helper method: $this->Number->method($args). 'Utility').56 $1. Release 2. Usage in a view looks like: // called as NumberHelper echo $this->Number->currency($number. // called as CakeNumber App::uses('CakeNumber'. Within a view. • $currency (string) – The known currency format to use. percentages.234. echo CakeNumber::currency($number. array $settings = array()) The NumberHelper contains convenient methods that enable display numbers in common formats in your views.CakePHP Cookbook Documentation. data sizes. These methods include ways to format currency.USD).

‘. If a non-recognized $currency value is supplied. Set to boolean false to use no decimal symbol. NumberHelper::defaultCurrency(string $currency) Parameters • $currency (string) – Set a known currency for CakeNumber::currency().35.56'. Defaults to 2.234. Setter/getter for default currency.’ Decimal separator symbol ie. 0. If equal to ‘()’. ‘ cents’ Either ‘before’ or ‘after’ to place the fraction symbol Fraction exponent of this specific currency. ‘Free!’ Number of decimal places to use. the number will be wrapped with ( and ) Should the output be htmlentity escaped? Defaults to true String to use for whole numbers ie.4: The fractionExponent option was added. Core Libraries . For example: // called as NumberHelper echo $this->Number->currency('1234. echo CakeNumber::currency('1234. ‘$’ The currency symbol to place after decimal numbers ie. it is prepended to a USD formatted number. ‘.56'. The text to use for zero values. 'Utility'). eg. array $options) Parameters • $formatName (string) – The format name to be used in the future 468 Chapter 7.3 NumberHelper::addFormat(string $formatName.3: This method was added in 2. 2 Thousands separator ie.CakePHP Cookbook Documentation. ie. 'FOO'). 0.35 => $0. 'FOO').x Option before after zero places thousands decimals negative escape wholeSymbol wholePosition fractionSymbol fractionPosition fractionExponent Description The currency symbol to place before whole numbers ie. Release 2. ‘ dollars’ Either ‘before’ or ‘after’ to place the whole symbol String to use for fraction numbers ie. Changed in version 2. This removes the need always passing the currency to CakeNumber::currency() and change all currency outputs by setting other default. can be a string or a number. New in version 2.’ Symbol for negative numbers.56 // called as CakeNumber App::uses('CakeNumber'. ‘c’. ie. // Outputs FOO 1.

'thousands' => '. // called as NumberHelper echo $this->Number->precision(456.x • $options (array) – The array of options for this format. array('before' => 'R$'. Release 2. It will round in order to maintain the level of precision defined. 0.92 // called as CakeNumber General Purpose 469 . 'decimals' => You can now use BRL as a short form when formatting currency amounts: // called as NumberHelper echo $this->Number->currency($value. '. 2 NumberHelper::precision(mixed $number. echo CakeNumber::currency($value. 'Utility'). 2. 'Utility'). 'BRL'). false. 'before'.'. 2). int $precision = 3) Parameters • $number (float) – The value to covert • $precision (integer) – The number of decimal places to display This method displays a number with the specified amount of precision (decimal places). Added formats are merged with the following defaults: array( 'wholeSymbol' 'wholePosition' 'fractionSymbol' 'fractionPosition' 'zero' 'places' 'thousands' 'decimals' 'negative' 'escape' 'fractionExponent' ) => => => => => => => => => => => ''. 'thousands' => '. 'after'. // Outputs 456. 'BRL'). Makes reusing currency formats easier: // called as NumberHelper $this->Number->addFormat('BRL'.91873645. true.'. 'decimals' // called as CakeNumber App::uses('CakeNumber'. $options keys as CakeNumber::currency(). CakeNumber::addFormat('BRL'. '()'. array('before' => 'R$'.'.CakePHP Cookbook Documentation. Uses the same Add a currency format to the Number helper. // called as CakeNumber App::uses('CakeNumber'.'. '.

echo CakeNumber::toPercentage(45. The size is displayed with a two-digit precision level. int $precision = 2. 2).e.91873645.45691. Option multiply Description Boolean to indicate whether the value has to be multiplied by 100. Release 2.4: The $options argument with the multiply option was added.CakePHP Cookbook Documentation.x App::uses('CakeNumber'. This method unformats a number from a human readable byte size to an integer number of bytes. This method also expresses the number as a percentage and prepends the output with a percent sign. see below. • $precision (integer) – The number of decimal places to display.69% echo CakeNumber::toPercentage(0. 'Utility'). GB. Core Libraries . Like precision().69% echo $this->Number->toPercentage(45. echo CakeNumber::precision(456. Useful for decimal percentages. This method formats data sizes in human readable forms. // Called with multiply. according to the size of data supplied (i.691873645). array( 'multiply' => true )). and TB. 'Utility'). Output: 45.3: This method was added in 2. array $options = array()) Parameters • $number (float) – The value to covert. Output: 45. this method formats a number according to the supplied precision (where numbers are rounded to meet the given precision). // Called as CakeNumber.691873645).69% App::uses('CakeNumber'. New in version 2.3 NumberHelper::toReadableSize(string $dataSize) Parameters • $dataSize (string) – The number of bytes to make readable. 2. // Called as NumberHelper. NumberHelper::fromReadableSize(string $size. Output: 45. higher sizes are expressed in larger terms): 470 Chapter 7. • $options (array) – Options. New in version 2. NumberHelper::toPercentage(mixed $number. $default) Parameters • $size (string) – The formatted human readable value. MB. It provides a shortcut way to convert bytes to KB.

'.00 GB // called as CakeNumber App::uses('CakeNumber'. $options). . Using this method might looks like: // called as NumberHelper $this->Number->format($number. // 0 Bytes echo $this->Number->toReadableSize(1024). 'decimals' => '.456. // output '¥ 123. Note that the default precision is zero decimal places. places Example: // called as NumberHelper echo $this->Number->format('123456. // 1 KB echo CakeNumber::toReadableSize(1321205. 'thousands' => '.x // called as NumberHelper echo $this->Number->toReadableSize(0). // 5. // 0 Bytes echo CakeNumber::toReadableSize(1024).236. 'before' => '¥ '. The $options parameter is where the real magic for this method resides. // 1 KB echo $this->Number->toReadableSize(1321205.26 MB echo $this->Number->toReadableSize(5368709120). // 1. . array( 'places' => 2. 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. •If you pass an integer then this becomes the amount of precision or places for the function.76).00 GB NumberHelper::format(mixed $number. The $number parameter is the number that you are planning on formatting for output.26 MB echo CakeNumber::toReadableSize(5368709120). •If you pass an associated array. 'Utility').' )). $options). With no $options supplied. the number 1236. // 1. echo CakeNumber::toReadableSize(0). 'escape' => false.7890'.334 would output as 1. millions. Release 2. .79' General Purpose 471 . // 5. 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).76). // called as CakeNumber CakeNumber::format($number.CakePHP Cookbook Documentation.

$options). array( 'places' => 2.79' // called as CakeNumber App::uses('CakeNumber'. Core Libraries .79' NumberHelper::formatDelta(mixed $number. $options).' )).236. 'decimals' => '. // output '¥ 123. .'.7890'. . places Example: // called as NumberHelper echo $this->Number->formatDelta('123456.456.456. 'Utility'). The $number parameter is the number that you are planning on formatting for output. echo CakeNumber::format('123456. // called as CakeNumber CakeNumber::formatDelta($number. echo CakeNumber::formatDelta('123456.79' New in version 2.'. 'decimals' => '. 'decimals' => '. With no $options supplied. 'escape' => false. 'thousands' => '.'. mixed $options=array()) This method displays differences in value as a signed number: // called as NumberHelper $this->Number->formatDelta($number. Release 2.7890'.x // called as CakeNumber App::uses('CakeNumber'. The $options parameter takes the same keys as CakeNumber::format() itself: •places (integer): the amount of desired precision •before (string): to be put before the outputted number •after (string): to be put after the outputted number •decimals (string): used to delimit the decimal places in a number •thousands (string): used to mark off thousand. the number 1236. 'before' => '¥ '. 'Utility').334 would output as 1. millions.7890'. array( 'places' => 2. 'thousands' => '. 'thousands' => '.' )). array( 'places' => 2. Note that the default precision is zero decimal places.3: This method was added in 2. // output '+123.456. // output '+123. .3 472 Chapter 7.CakePHP Cookbook Documentation.' )).

Release 2. New in version 2. • lock Lock direction. Output: General Purpose 473 . It works in tandem with PaginatorComponent. 'User account'). Assuming you are paginating some posts. Accepted keys for $options: • escape Whether you want the contents HTML entity encoded. array $settings = array()) The Pagination helper is used to output pagination controls such as page numbers and next/previous links. defaults to PaginatorHelper::defaultModel(). • direction The default direction to use when this link isn’t active.4 the symbols are now UTF-8. • $title (string) – Title for the link.CakePHP Cookbook Documentation. Please see the migration guide for details if you run a non-UTF-8 app. defaults to true. and are on page one: echo $this->Paginator->sort('user_id'). links generated with sort() will handle direction switching automatically. defaults to false. • $options (array) – Options for sorting link. See also Pagination for information on how to create paginated datasets and do paginated queries. Link sorting default by ‘asc’. If the resultset is sorted ‘asc’ by the specified key the returned link will sort by ‘desc’. • model The model to use.x Warning: Since 2. Output: <a href="/posts/index/page:1/sort:user_id/direction:asc/">User Id</a> You can use the title parameter to create custom text for your link: echo $this->Paginator->sort('user_id'. If $title is null $key will be used for the title and will be generated by inflection. $options = array()) Parameters • $key (string) – The name of the key that the recordset should be sorted.5: You can now set the lock option to true in order to lock the sorting direction into the specified direction. $title = null. Generates a sorting link. PaginatorHelper class PaginatorHelper(View $view. Creating sort links PaginatorHelper::sort($key. Will only use the default direction then. Sets named or querystring parameters for the sort and direction. Links will default to sorting by asc. After the first click.

Uses a modulus to decide how many numbers to show on each side of the current page By default 8 links on either side of the current page will be created if those pages exist. PaginatorHelper::sortKey(string $model = null. • modulus how many numbers to include on either side of the current page. • separator Separator content defaults to ‘‘ | ‘‘ • tag The tag to wrap links in. mixed $options = array()) Gets the current key by which the recordset is sorted. • model Model to create numbers for. array('escape' => false) ). Output: <a href="/posts/index/page:1/sort:user_id/direction:desc/">User Id</a> The lock option can be used to lock sorting into the specified direction: echo $this->Paginator->sort('user_id'. null. 'lock' => true)). defaults to 8. array('direction' => 'desc')). '<em>User account</em>'. defaults to PaginatorHelper::defaultModel(). Output: <a href="/posts/index/page:1/sort:user_id/direction:asc/"> <em>User account</em> </a> The direction option can be used to set the default direction for a link. defaults to ‘span’.x <a href="/posts/index/page:1/sort:user_id/direction:asc/">User account</a> If you are using HTML like images in your links remember to set escaping off: echo $this->Paginator->sort( 'user_id'. Once a link is active. Creating page number links PaginatorHelper::numbers($options = array()) Returns a set of numbers for the paged result set. PaginatorHelper::sortDir(string $model = null. Links will not be generated for pages that do not exist. it will automatically switch directions like normal: echo $this->Paginator->sort('user_id'. array('direction' => 'asc'. Release 2. • after Content to be inserted after the numbers. 474 Chapter 7. Supported options are: • before Content to be inserted before the numbers.CakePHP Cookbook Documentation. The current page is also not a link. Core Libraries . mixed $options = array()) Gets the current direction the recordset is sorted. null.

Release 2.CakePHP Cookbook Documentation. defaults to ‘span’. first and last pages in the paged data set. • currentClass The class name to use on the current/active link. PaginatorHelper::prev($title = ‘<< Previous’. There is a last()‘ method to be used separately as well if you wish. If a string is set a link to the first page will be generated with the value as the title: echo $this->Paginator->numbers(array('first' => 'First page')). • ellipsis Ellipsis content. General Purpose 475 . set to an integer to define the number of ‘first’ links to generate.1: The currentClass option was added in 2. $options and $disabledOptions supports the following keys: •tag The tag wrapping tag you want to use. Defaults to false. $disabledTitle = null. Defaults to false. Set this to false to disable this option..’ • class The class name used on the wrapping tag. • $options (mixed) – Options for pagination link.3: The currentTag option was added in 2. defaults to null. New in version 2. This allows you to generate for example Twitter Bootstrap like links with the current page number wrapped in extra ‘a’ or ‘span’ tag.1. While this method allows a lot of customization for its output. • last Whether you want last links generated. New in version 2. Using the first and last options you can create links to the beginning and end of the page set. defaults to ‘. no previous page to go. $disabledOptions = array()) Parameters • $title (string) – Title for the link. • currentTag Tag to use for current page number.x • first Whether you want first links generated. echo $this->Paginator->numbers(). • $disabledTitle (string) – Title when the link is disabled. It is also ok to just call the method without any params. • $disabledOptions (mixed) – Options for the disabled pagination link. you’ll often want links that go to the previous and next links.. Defaults to current. The following would create a set of page links that include links to the first 2 and last 2 pages in the paged results: echo $this->Paginator->numbers(array('first' => 2. $options = array(). as when you’re already on the first page. Creating jump links In addition to generating links that go directly to specific page numbers. Follows the same logic as the first option. 'last' => 2)). set to an integer to define the number of ‘last’ links to generate.3. Generates a link to the previous page in a set of paged records.

array('tag' => 'li')). Output: <li class="prev"> <a rel="prev" href="/posts/index/page:1/sort:title/order:desc"> previous </a> </li> You can also disable the wrapping tag: echo $this->Paginator->prev(__('previous'). •disabledTag Tag to use instead of A tag when there is no previous page A simple example would be: echo $this->Paginator->prev( ' << ' . null. If you were currently on the second page of posts. This can save some additional typing if both sets of options are the same. Core Libraries .x •escape Whether you want the contents HTML entity encoded. array('class' => 'prev disabled') ). you would get the following: <span class="prev"> <a rel="prev" href="/posts/index/page:1/sort:title/order:desc"> << previous </a> </span> If there were no previous pages you would get: <span class="prev disabled"><< previous</span> You can change the wrapping tag using the tag option: echo $this->Paginator->prev(__('previous'). Output: <a class="prev" rel="prev" href="/posts/index/page:1/sort:title/order:desc"> previous </a> Changed in version 2. array().CakePHP Cookbook Documentation. defaults to true. 476 Chapter 7. New options disabledTag has been added. array('tag' => false)). If you leave the $disabledOptions empty the $options parameter will be used. •model The model to use. defaults to PaginatorHelper::defaultModel().3: For methods: PaginatorHelper::prev() and PaginatorHelper::next() it is now possible to set the tag option to false to disable the wrapper. Release 2. __('previous').

You can also use an integer to indicate how many first paging links you want generated: echo $this->Paginator->first(3). Will output nothing if you are on the first page. It creates links pointing to the next page instead of the previous one. once you get to the third or greater page. $disabledOptions = array()) This method is identical to prev() with a few exceptions. // Output is 3 PaginatorHelper::hasNext(string $model = null) Returns true if the given result set is not at the last page.com/comments/view/page:3 echo $this->Paginator->current('Comment'). $options = array(). For an integer value of $last no links will be generated once the user is inside the range of last pages. defaults to ‘span’ •after Content to insert after the link/tag •model The model to use defaults to PaginatorHelper::defaultModel() •separator Content between the generated links.x PaginatorHelper::next($title = ‘Next >>’.. defaults to ‘. The options parameter accepts the following: •tag The tag wrapping tag you want to use. then only a link to the first page with the provided text will be created: echo $this->Paginator->first('< first'). If a string is given. The above creates a single link for the first page. PaginatorHelper::hasPrev(string $model = null) Returns true if the given result set is not at the first page. integer $page = 1) Returns true if the given result set has the page number given by $page. PaginatorHelper::hasPage(string $model = null. Prior to that nothing will be output.CakePHP Cookbook Documentation. $options = array()) This method works very much like the first() method. The above will create links for the first 3 pages. defaults to ‘ | ‘ •ellipsis Content for ellipsis. It will not generate any links if you are on the last page for a string values of $last. It also uses next as the rel attribute value instead of prev PaginatorHelper::first($first = ‘<< first’.. Creating a page counter PaginatorHelper::counter($options = array()) General Purpose 477 . $options = array()) Returns a first or set of numbers for the first pages. $disabledTitle = null. Release 2.’ PaginatorHelper::last($last = ‘last >>’. PaginatorHelper::current(string $model = null) Gets the current page of the recordset for the given model: // Our URL is: http://example. It has a few differences though.

Supported options are: 478 Chapter 7. Using a provided format string and a number of options you can create localized and application specific indicators of where a user is in the paged data set. ‘pages’ and custom.current number of records being shown. – {:pages} . For example: echo $this->Paginator->counter( 'Page {:page} of {:pages}.0. The supported ones are: • format Format of the counter.The pluralized human form of the model name. If a string is supplied . • separator The separator between the actual page and the number of pages. Supported formats are ‘range’. Setting ‘format’ to range would output like ‘1 . If your model was ‘RecipePage’. starting on record {:start}. In the custom mode the supplied string is parsed and tokens are replaced with actual values.CakePHP Cookbook Documentation. You could also supply only a string to the counter method using the tokens available. Modifying the options PaginatorHelper uses PaginatorHelper::options($options = array()) Parameters • $options (mixed) – Default options for pagination links. This is used in conjunction with the custom string on ‘format’ option.x Returns a counter string for the paged result set.it is used as the DOM id element to update. {:model} would be ‘recipe pages’. showing {:current} records out of {:count} total.the current page displayed. – {:start} .number of the first record being displayed. – {:end} . Defaults to pages which would output like ‘1 of 10’.3 of 13’: echo $this->Paginator->counter(array( 'format' => 'range' )). There are a number of options for counter(). – {:model} . Release 2. Defaults to ‘ of ‘. • model The name of the model being paginated.total number of pages. Sets all the options for the Paginator Helper.number of the last record being displayed. – {:count} . This option was added in 2. This is used in conjunction with ‘format’ = ‘pages’ which is ‘format’ default value: echo $this->Paginator->counter(array( 'separator' => ' of a total of ' )).the total number of records in the result set. Core Libraries . defaults to PaginatorHelper::defaultModel(). – {:current} . The available tokens are: – {:page} . ending on {:end}' ).

There are times you want to use GET parameters instead. if you don’t want that and want to use a custom helper for AJAX links. 'here') )). 'keys'. However. • escape Defines if the title field for links should be HTML escaped. Configuring the PaginatorHelper to use a JavaScript helper By default the PaginatorHelper uses JsHelper to do AJAX features. you can do so by changing the $helpers array in your controller. So you don’t have to do that in each view file.CakePHP Cookbook Documentation. – page The page number to display. Release 2. Defaults to true. defaults to Using GET parameters for pagination Normally Pagination in CakePHP uses Named Parameters. you have some additional control in the view. The above mentioned options can be used to force particular pages/directions. This is useful when doing AJAX Pagination. – direction The direction of the sorting. $this->set('posts'. You can use options() to indicate that you want other named parameters to be converted: $this->Paginator->options(array( 'convertKeys' => array('your'. but most often is simpler to use an id selector. • update The CSS selector of the element to update with the results of AJAX pagination calls.x • url The URL of the paginating action. direction and page values. ‘url’ has a few sub options as well: – sort The key that the records are sorted by. While the main configuration option for this feature is in PaginatorComponent. Defaults to ‘ASC’. 'lang' => 'en' ) )). If not specified. You can also append additional URL content into all URLs generated in the helper: $this->Paginator->options(array( 'url' => array( 'sort' => 'email'. The above adds the en route parameter to all links the helper will generate. being paginated. After running paginate() do the following: // In your controller action. 'page' => 6. General Purpose 479 . $this->helpers['Paginator'] = array('ajax' => 'CustomJs'). It will also create links with specific sort. Keep in mind that the value of update can be any valid CSS selector. By default PaginatorHelper will merge in all of the current pass and named parameters. $this->paginate()). 'direction' => 'desc'. regular links will be created: $this->Paginator->options(array('update' => '#content')). • model The name of the model PaginatorHelper::defaultModel().

As mentioned. The examples below assume a tabular layout.org/2. as long as that class implements a link() method that behaves like HtmlHelper::link() Pagination in Views It’s up to you to decide how to show records to the user. Release 2. // Shows the next and previous links echo $this->Paginator->prev( 6 http://api. 'Author').name'. ?> </table> The final ingredient to pagination display in views is the addition of page navigation.x Will change the PaginatorHelper to use the CustomJs for AJAX operations. ?></th> <th><?php echo $this->Paginator->sort('Author. ?></th> <th><?php echo $this->Paginator->sort('title'. ?> </td> </tr> <?php endforeach.8/class-PaginatorHelper. also supplied by the PaginationHelper: // Shows the page numbers echo $this->Paginator->numbers(). Core Libraries . ?> </td> <td><?php echo h($recipe['Author']['name']). the PaginatorHelper also offers sorting features which can be easily integrated into your table column headers: // app/View/Posts/index. ?> </td> <td><?php echo h($recipe['Recipe']['title']). ?></th> </tr> <?php foreach ($data as $recipe): ?> <tr> <td><?php echo h($recipe['Recipe']['title']). See the details on PaginatorHelper6 in the API. 'ID'). You could also set the ‘ajax’ key to be any helper. 'Title'). It is also possible to sort a column based on associations: <table> <tr> <th><?php echo $this->Paginator->sort('title'. ?> </table> The links output from the sort() method of the PaginatorHelper allow users to click on table headers to toggle the sorting of the data by a given field.cakephp. ?> </td> </tr> <?php endforeach.html 480 Chapter 7.ctp <table> <tr> <th><?php echo $this->Paginator->sort('id'. but most often this will be done inside HTML tables. but the PaginatorHelper available in views doesn’t always need to be restricted as such.CakePHP Cookbook Documentation. 'Title'). ?></th> </tr> <?php foreach ($data as $recipe): ?> <tr> <td><?php echo $recipe['Recipe']['id'].

Other Methods PaginatorHelper::link($title. ending on {:end}' )). Release 2. $model = null) pointing at Parameters • $options (array) – Pagination/URL options array.CakePHP Cookbook Documentation. The wording output by the counter() method can also be customized using special markers: echo $this->Paginator->counter(array( 'format' => 'Page {:page} of {:pages}. 'direction' => 'desc')). null. As used on options() or link() method. • $url (mixed) – Url for the action. null. •escape Whether you want the contents HTML entity encoded. $asArray = false.x '« Previous'. where X is current page and Y is number of pages echo $this->Paginator->counter(). $url = array(). echo $this->Paginator->next( 'Next »'. defaults to PaginatorHelper::defaultModel(). array('class' => 'disabled') ). If created in the view for /posts/index Would create a link ‘/posts/index/page:5/sort:title/direction:desc’ PaginatorHelper::url($options = array(). defaults to true. •model The model to use. Creates a regular or AJAX link with pagination parameters: echo $this->Paginator->link('Sort by title on page 5'. Creates AJAX enabled links. // prints X of Y. null. null. showing {:current} records out of {:count} total. General Purpose 481 . $options = array()) Parameters • $title (string) – Title for the link. See options() for list of keys. array('class' => 'disabled') ). 'page' => 5. See Router::url() • $options (array) – Options for the link. starting on record {:start}. Accepted keys for $options: •update The Id of the DOM element you wish to update. array('sort' => 'title'.

/* Array ( [page] => 2 [current] => 2 [count] => 43 [prevPage] => 1 [nextPage] => 3 [pageCount] => 3 [order] => [limit] => 20 [options] => Array ( [page] => 2 [conditions] => Array ( ) ) [paramType] => named ) */ PaginatorHelper::param(string $key.CakePHP Cookbook Documentation. Core Libraries . PaginatorHelper::params(string $model = null) Gets the current paging parameters from the resultset for the given model: debug($this->Paginator->params()). PaginatorHelper::meta(array $options = array()) Outputs the meta-links for a paginated result set: echo $this->Paginator->meta(). true). or a URI string. PaginatorHelper::defaultModel() Gets the default model of the paged sets or null if pagination is not initialized. Defaults to false.4.x • $asArray (boolean) – Return the URL as an array. /* (int)43 */ New in version 2. • $model (string) – Which model to paginate on By default returns a full pagination URL string for use in non-standard contexts (i.e. string $model = null) Gets the specific paging parameter from the resultset for the given model: debug($this->Paginator->param('count')). JavaScript). // Example output for page 5 /* <link href="/?page=4" rel="prev" /><link href="/?page=6" rel="next" /> */ 482 Chapter 7. Release 2.4: The param() method was added in 2. echo $this->Paginator->url(array('sort' => 'title').

first we need to edit the controller to add in the rss-specific code. so that should be added to the controller as well: public $helpers = array('Text'). This will allow a lot of automagic to occur: public $components = array('RequestHandler'). 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. However. RssHelper class RssHelper(View $view. Release 2.6: The meta() method was added in 2.CakePHP Cookbook Documentation.rss extension. Creating an xml/rss version of posts/index is a snap with CakePHP. This will activate each extension/content-type for use in your application. Before we can make an RSS version of our posts/index we need to get a few things in order. Controller Code It is a good idea to add RequestHandler to your PostsController’s $components array. Before we jump too far ahead trying to get our webservice up and running we need to do a few things.rss. In the call above we’ve activated the . this is done in app/Config/routes.6.x You can also append the output of the meta function to the named block: $this->Paginator->meta(array('block' => true)). 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.rss to posts/index making your URL posts/index. array $settings = array()) The RSS helper makes generating XML for RSS feeds easy. First parseExtensions needs to be activated. Creating an RSS feed with the RssHelper This example assumes you have a Posts Controller and Post Model already created and want to make an alternative view for RSS. Now when the address posts/index. When using Router::parseExtensions() you can pass as many arguments or extensions as you want. That will come later though. New in version 2. Our view will also use the TextHelper for formatting.php: Router::parseExtensions('rss'). If true is passed. which is the // index action in our example public function index() { if ($this->RequestHandler->isRss() ) { General Purpose 483 .rss is requested you will get an xml version of your posts/index. otherwise your controller can stay the same: // Modify the Posts Controller action that corresponds to // the action which deliver the rss feed. After a few simple steps you can simply append the desired extension . the “meta” block is used. That information can also go in the view.

Which is where our $channelData array will come from setting all of the meta data for our feed.ctp: put the following contents in if (!isset($documentData)) { $documentData = array(). 484 Chapter 7. $this->fetch('content')).created DESC') ).created DESC'.ctp inside that folder. we need to create a View/Posts/rss/ directory and create a new index. } if (!isset($channelData)) { $channelData = array(). View Our view. $this->set(compact('posts')). 'order' => 'Post. app/View/Layouts/rss/default. Core Libraries . } // this is not an Rss request. array( 'title' => __("Most Recent Posts"). return $this->set(compact('posts')). array('limit' => 20. Layout An Rss layout is very simple. $channelData. $channel). so deliver // data used by website's interface $this->paginate['Post'] = array( 'order' => 'Post. these contain all the metadata for our RSS feed. Next up is view file for my posts/index. } if (!isset($channelData['title'])) { $channelData['title'] = $this->fetch('title').x $posts = $this->Post->find( 'all'. begins by setting the $documentData and $channelData variables for the layout. This is done by using the View::set() method which is analogous to the Controller::set() method. } $channel = $this->Rss->channel(array().CakePHP Cookbook Documentation.ctp. It doesn’t look like much but thanks to the power in the RssHelper it’s doing a lot of lifting for us. $posts = $this->paginate(). however in CakePHP your views can pass variables back to the layout. Much like the layout file we created. The contents of the file are below. } With all the View variables set we need to create an rss layout. Here though we are passing the channel’s metadata back to the layout: $this->set('channelData'. Release 2. located at app/View/Posts/rss/index. We haven’t set $documentData or $channelData in the controller. 'limit' => 10 ). echo $this->Rss->document($documentData.

'year' => date('Y'. $bodyText = $this->Text->truncate($bodyText. // Remove & escape any HTML to make sure the feed content will validate. It is important to filter out any non-plain text characters out of the description. Once we have set up the data for the feed. as they could cause validation errors. 'exact' => true. foreach ($posts as $post) { $postTime = strtotime($post['Post']['created']). There is one downfall to this method. The RssHelper::item() transforms the associative array into an element for each key value pair. 'link' => $postLink. )). General Purpose 485 . we can then use the RssHelper::item() method to create the XML in RSS format. $postTime). $postTime). 'description' => __("Most recent posts. } You can see above that we can use the loop to prepare the data to be transformed into XML elements. This is accomplished by looping through the data that has been passed to the view ($items) and using the RssHelper::item() method. echo $this->Rss->item(array(). 'pubDate' => $post['Post']['created'] )).. The other method you can use. Note: You will need to modify the $postLink variable as appropriate to your application. array( 'title' => $post['Post']['title']. $postTime). 'guid' => array('url' => $postLink. 'month' => date('m'.CakePHP Cookbook Documentation. 'language' => 'en-us' )). In the code above we used strip_tags() and h() to remove/escape any XML special characters from the content. 'action' => 'view'.. $bodyText = h(strip_tags($post['Post']['body']))."). RssHelper::items() which takes a callback and an array of items for the feed. thus not giving access to the TimeHelper or any other helper that you may need. 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. 'description' => $bodyText.x 'link' => $this->Html->url('/'. especially if you are using a rich text editor for the body of your blog. Release 2. The second part of the view generates the elements for the actual records of the feed.'. $post['Post']['slug'] ). 400. 'isPermaLink' => 'true'). true). 'day' => date('d'. array( 'ending' => '. $postLink = array( 'controller' => 'posts'. 'html' => true. (The method I have seen used for the callback has always been called transformRss().

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. Note: You may need to set the value of ‘debug’ in your core configuration to 1 or to 0 to get a valid feed. Rss Helper API property RssHelper::$action Current action property RssHelper::$base Base URL property RssHelper::$data POSTed model data property RssHelper::$field Name of the current field property RssHelper::$helpers Helpers used by the RSS Helper property RssHelper::$here URL to current action property RssHelper::$model Name of current model property RssHelper::$params Parameter array property RssHelper::$version Default spec version of generated RSS. mixed $content = null. RssHelper::channel(array $attrib = array (). string $content = null) Return type string Returns an RSS document wrapped in <rss /> tags. array $elements = array ().CakePHP Cookbook Documentation. mixed $content = null) Return type string Returns an RSS <channel /> element. 486 Chapter 7.x Once you have all this setup. array $attrib = array ().rss and you will see your new feed. you can test your RSS feed by going to your site /posts/index. boolean $endTag = true) Return type string Generates an XML element. RssHelper::document(array $attrib = array ().org/feed/. Core Libraries . because of the various debug information added automagically under higher debug settings that break XML syntax or feed validation rules. Release 2.w3. RssHelper::elem(string $name.

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. RssHelper::time(mixed $time) Return type string Converts a time in any format to an RSS time. SessionHelper::check(string $key) Return type boolean Check to see whether a key is in the Session. mixed $callback = null) Return type string Transforms an array of data using an optional callback. and maps it to a set of <item /> tags. Given the previous array structure.x RssHelper::item(array $att = array ().CakePHP Cookbook Documentation. the node would be accessed by User. Returns a string or array depending on the contents of the session.com' )). As with the Session Component. RssHelper::items(array $items. array $settings = array()) As a natural counterpart to the Session Component. the Session Helper replicates most of the component’s functionality and makes it available in your view. array $elements = array ()) Return type string Converts an array into an <item /> element and its contents. See TimeHelper::toRSS(). This is useful when you want to combine reading and deleting values in a single operation. This notation is used for all Session helper methods wherever a $key is used.username. with the dot indicating the nested array. Returns a boolean representing the key’s existence. SessionHelper::read(string $key) Return type mixed Read from the Session. Release 2. data is read by using dot notation array structures: array('User' => array( 'username' => 'super@example. SessionHelper::consume($name) Return type mixed Read and delete a value from the Session. SessionHelper::error() Return type string General Purpose 487 . SessionHelper class SessionHelper(View $view.

The message text would be available as $message in the element.x Returns last error encountered in a session.CakePHP Cookbook Documentation. which allows you to generate customized messages: // In the controller $this->Session->setFlash('Thanks for your payment. Once a message is displayed.7. array( 'params' => array('name' => $user['User']['name']) 'element' => 'payment' )). The above will output a simple message with the following HTML: <div id="flashMessage" class="message"> Your stuff has been saved. you can create one-time notifications for feedback. array('element' => 'failure')). you can set additional properties and customize which element is used.ctp to render the message. Release 2. echo $this->Session->flash('flash'. echo $this->Session->flash('flash'.'). 488 Chapter 7. // In the layout.'). This would use View/Elements/failure. you can choose the element used to display the message: // in a layout. you will want to display them. SessionHelper::valid() Return type boolean Used to check whether a session is valid in a view. it will be removed and not displayed again: echo $this->Session->flash(). Displaying notifications or flash messages SessionHelper::flash(string $key = ‘flash’. After creating messages with SessionComponent::setFlash(). </div> As with the component method. you might have code like: // in a controller $this->Session->setFlash('The user could not be deleted. In the controller. Core Libraries . When outputting this message. As explained in Creating notification messages. The failure element would contain something like this: <div class="flash flash-failure"> <?php echo h($message).0: You should use FlashHelper to render flash messages. ?> </div> You can also pass additional parameters into the flash() method. array $params = array()) Deprecated since version 2.

Output: For more information regarding our world-famous pastries and desserts. these methods are accessible via the TextHelper class. h($name)). Adds links to the well-formed email addresses in $text.CakePHP Cookbook Documentation. contact <a href="mailto:info@example.x // View/Elements/payment. formatting URLs. • $options (array) – An array of html attributes for the generated links. You can call one as you would call a normal helper method: $this->Text->method($args). If you are using any request or user data in your flash messages.com</a> Changed in version 2.ctp <div class="flash payment"> <?php printf($message. TextHelper class TextHelper(View $view. http.1: In 2. • $options (array) – An array html attributes for the generated links Same as autoLinkEmails().1 this method automatically escapes its input. Use the escape option to disable this if necessary. only this method searches for strings that start with https. TextHelper::autoLinkEmails(string $text. $linkedText = $this->Text->autoLinkEmails($myText). array $settings = array()) The TextHelper contains methods to make text more usable and friendly in your views. $myText = 'For more information regarding our world-famous ' . ftp. 'pastries and desserts. you should escape it with h when formatting your messages.1: Several TextHelper methods have been moved into the String class to allow easier use outside of the View layer. according to any options defined in $options (see HtmlHelper::link()). Release 2.. General Purpose 489 . or nntp and links them appropriately. array $options=array()) Parameters • $text (string) – The text to convert. creating excerpts of text around chosen words or phrases. Within a view.com'. highlighting key words in blocks of text. TextHelper::autoLinkUrls(string $text. and gracefully truncating long stretches of text. CakePHP does not escape the HTML in flash messages. array $options=array()) Parameters • $text (string) – The text to convert. Changed in version 2. ?> </div> Note: By default. It aids in enabling links. contact info@example.com">info@example.

$formattedText = $this->Text->autoParagraph($myText).string The piece of HTML with that the phrase will be highlighted •‘html’ . array $options=array()) Parameters • $text (string) – The text to autolink. • $options (array) – An array of options.<p> <p>contact info@example. $myText = 'For more information regarding our world-famous pastries and desserts. Adds proper <p> around text where double-line returns are found. Use the escape option to disable this if necessary.1: In 2. Release 2. TextHelper::highlight(string $haystack. string $needle. array $options = array()) Parameters • $haystack (string) – The string to search. All URLs and emails are linked appropriately given the supplied $options.1: As of 2.1 this method automatically escapes its input. see below. Options: •‘format’ . contact info@example. Core Libraries . • $options (array) – An array html attributes for the generated links Performs the functionality in both autoLinkUrls() and autoLinkEmails() on the supplied $text.4.com'.1. Output: <p>For more information<br /> regarding our world-famous pastries and desserts.com</p> New in version 2.x Changed in version 2. • $needle (string) – The string to find. ensuring that only the correct text is highlighted 490 Chapter 7. Changed in version 2. Highlights $needle in $haystack using the $options[’format’] string specified or a default string. this method automatically escapes its input. Use the escape option to disable this if necessary. TextHelper::autoLink(string $text.bool If true. TextHelper::autoParagraph(string $text) Parameters • $text (string) – The text to convert.CakePHP Cookbook Documentation. will ignore any HTML tags. and <br> where single-line returns are found.

and has the following possible keys by default.'. HTML tags will be respected and will not be cut off. array('format' => '<span class="highlight">\1</span>') ).x Example: // called as TextHelper echo $this->Text->highlight( $lastSentence. TextHelper::truncate(string $text. array('format' => '<span class="highlight">\1</span>') ). Release 2. If $text is longer than $length characters. this method truncates it at $length and adds a prefix consisting of ’ellipsis’. 'using'. 'html' => false ) Example: // called as TextHelper echo $this->Text->truncate( 'The killer crept forward and tripped on the rug. if defined.. in characters. $options is used to pass all extra parameters. TextHelper::stripLinks($text) Strips the supplied $text of any HTML links. int $length=100.. array $options) Parameters • $text (string) – The text to truncate. Output: Highlights $needle in $haystack <span class="highlight">using</span> the $options['format'] string specified or a default string. all of which are optional: array( 'ellipsis' => '. General Purpose 491 .CakePHP Cookbook Documentation. the truncation will occur at the first whitespace after the point at which $length is exceeded. 'Utility').'. If ’html’ is passed as true. 'using'. • $options (array) – An array of options to use. echo CakeText::highlight( $lastSentence. • $length (int) – The length. If ’exact’ is passed as false. beyond which the text should be truncated. // called as CakeText App::uses('CakeText'. 'exact' => true. 22.

death metal t-shirts' // called as TextHelper echo $this->Text->tail( 492 Chapter 7.. int $length=