Key Takeaways
- CakePHP is a popular PHP framework designed to provide structure and organization to PHP applications, inspired by the features and functionality of Ruby on Rails.
- The MVC (Model-View-Controller) architecture in CakePHP helps separate business logic from data and presentation layers, enhancing maintainability and organization of code.
- CakePHP emphasizes convention over configuration, meaning less setup for developers as the framework assumes logical placement of elements (like controllers and models).
- Scaffolding in CakePHP allows for rapid creation of basic CRUD (Create, Read, Update, Delete) functionalities with minimal coding, making it ideal for quick prototyping.
- CakePHP supports both PHP4 and PHP5, ensuring compatibility across different server environments.
- The framework includes built-in tools for security such as input validation, CSRF protection, and SQL injection prevention, making it a secure option for developing robust web applications.
PHP Needs a Framework
In recent years, PHP has re-invented itself, allowing Object Oriented Programming (OOP) to enter the scene with a plethora of new rules and functionality, all of which are ingrained in more mainstream programming languages like C++ and Java. Gradually, more and more PHP developers have embraced this new philosophy and started developing frameworks, drawing their inspiration from other more-established languages in the pursuit of creating a structure for an inherently unstructured language. Many frameworks are available on the Internet, each with its own specific set of rules and conventions, achievements and failures. Some degenerate into unusable and intricate collections of pre-built libraries and tools that enslave developers into complex and truly unusable programming methodologies; others do not. Ruby on Rails has definitely played a key role in inspiring the quest for the perfect web framework in programming languages other than Ruby. Thanks to the Rails phenomenon, more frameworks have appeared on the scene, offering functionality that’s very similar to Ruby on Rails. These frameworks are often labeled Rails Clones. Some of the frameworks’ developers have openly admitted that they tried to port Rails to other languages, but often they overlook the fact that Ruby on Rails was built in Ruby for a reason: Ruby has features that no other programming language offers. At the same time, at least one person gave up on the idea of totally cloning Rails in PHP, but instead, decided to borrow its structure and basic concepts to make PHP more organized:While it’s difficult to copy Rails in PHP, it’s quite possible to write an equivalent system. I like the terseness of Ruby code, but I need the structure that Rails provides, how it makes me organize my code into something sustainable. That’s why I’m ripping off Rails in Cake.– CakePHP’s founder, commenting on a famous blog post. This is what makes CakePHP not only different, but one of the most popular frameworks for PHP: its modest, yet important goal is to provide an appropriate structure for PHP applications.
CakePHP’s Approach to the MVC Architecture
Readers who already know Ruby on Rails may find CakePHP very similar to it. For one thing, Cake is based on an MVC-like architecture that is both powerful and easy to grasp: controllers, models and views guarantee a strict but natural separation of business logic from data and presentation layers. Controllers contain the logic of your application. Each controller can offer different functionality; controllers retrieve and modify data by accessing database tables through models; and they register variables and objects, which can be used in views. Models are active representations of database tables: they can connect to your database, query it (if instructed to do so by a controller) and save data to the database. It is important to note that in order to correctly apply the MVC architecture, there must be no interaction between models and views: all the logic is handled by controllers.- It separates business logic from presentation and data retrieval.
- A site is divided into logical sections, each governed by a particular controller.
- When testing and debugging an application, any developer accustomed to CakePHP’s structure will be able to locate and correct errors without knowing all of the details of the code.
- app/
- config/
- controllers/
- models/
- plugins/
- tmp/
- vendors/
- views/
- webroot/
- cake/
- config/
- docs/
- libs/
- vendors/
Tasting the Batter
As an example, let’s now look at building a simple memo application that allows you to add, edit, display and delete personal notes, which are stored in a MySQL database. In order to try this yourself, you’ll need to download the latest stable version of CakePHP and ensure that your development environment meets the following requirements:- has access to a web server like Apache, although others like IIS and Lighttpd are supported
- has the ability to rewrite URLs (e.g. using the mod_rewrite module for Apache — by default CakePHP comes with a .htaccess file to handle this)
- has MySQL, or a similar database server installed, and you have the necessary privileges to create a new database; other solutions like PostgreSQL or SQLite should work, although MySQL is recommended (this example will assume that you are using MySQL)
- has PHP version 4.3 or above; CakePHP seamlessly supports both PHP4 and PHP5
http://localhost/
.
Confirming configuration of CakePHP
CREATE TABLE notes (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
Note how the table uses the plural notes. Now, edit your database configuration file (/app/config/database.php.default
) as follows, and save it as database.php
(yes: the name matters!):
<?php
class DATABASE_CONFIG
{
var $default = array('driver' => 'mysql',
'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => 'memouser',
'password' => 'userpassword',
'database' => 'memo' );
var $test = array('driver' => 'mysql',
'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name-test');
}
?>
If you refresh the default page, CakePHP will notify you that the database is now accessible.
CakePHP is now configured properly, and we can turn to the development of our application. The framework offers a useful Rails-inspired feature called scaffolding, which basically allows the creation of an interface that’s able to perform Create, Read, Update and Delete (CRUD) database operations with only a few lines of code. This is particularly useful when you want a particular area of your application to be available for testing purposes quickly, and you don’t want to spend time coding it properly — yet.
To create a scaffolded version of our memo application we need to create two very basic files: a controller and a model.
Create a file named note.php
(again, the name matters — notice how the file and the class defined here are the singular note of the database table notes) and save it in your /app/models/
directory. You need only include the following lines in it:
<?php
class Note extends AppModel
{
var $name = 'Note';
}
?>
Similarly, create a notes_controller.php
file containing the code below, and place it in /app/controllers/
.
<?php
class NotesController extends AppController
{
var $name = 'Notes';
var $scaffold;
}
?>
The $scaffold
variable will trigger CakePHP’s default scaffolding behavior: a fully-functional Notes section will be created, and will be accessible at http://localhost/notes/
.
That’s all there is to it. You are now able to create, update, delete and display your notes with (literally) five lines of PHP code!
The default edit view for a CakePHP application
This is an old trick, and if you’ve ever read a beginners’ tutorial to Ruby on Rails you probably won’t be too amazed; however, it’s nice to know that a formerly Rails-only feature has been ported to PHP.
Creating your First Application
After playing with your new application for a while — feel free to create and delete a few notes — you’ll start to notice its obvious limitations:- the layout is very plain, and apparently is not customizable
- notes are deleted without confirmation
- there’s no validation for any data input by users
http://localhost/notes/
http://localhost/notes/add/
http://localhost/notes/edit/1/
http://localhost/notes/view/2/
http://localhost/notes/delete/3/
In other words, all our URLs match a common pattern: they’re all written in the form /<controller>/<action>/<first_parameter>/
. So we need to create at least three views for the CRUD operations — we’ll name them add.thtml
, edit.thtml
and view.thtml
— as well as a default view (index.thtml
) to list and manage all of the notes. The “t” in these thtml
files indicates that these files are Cake templates. And what about delete.thtml
? This file does not need to be created; we’ll see why shortly.
Before proceeding, remove this line from your NotesController
class:
var $scaffold;
Viewing your Notes
The first view we should create is a list of all the notes stored in the database, which will be the default page that displays when we access http://localhost/notes/
. Create a new subdirectory named notes
in your /app/views/
directory, then create a new file named index.thtml
inside that. This file should contain the following code:
<h1>My Notes</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<?php foreach ($notes as $note): ?>
<tr>
<td><?php echo $note['Note']['id']; ?></td>
<td>
<a href="/notes/view/<?php echo $note['Note']['id']?>">
<?php echo $note['Note']['title']?>
</a>
</td>
<td><?php echo $note['Note']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>
Note that our template code is not a complete HTML document — things like the doctype and header information for all files is also provided by the framework, and the default can of course be overridden later.
This should display a list of all the stored notes, but if you try accessing http://localhost/notes/
right now, you’ll get an error saying that the action index is not defined in your controller.
The code for this action needs to be created in your controller. It simply needs to retrieve all records from your notes database table and store them in an array. Cake achieves this task in one line of code:
function index()
{
$this->set('notes', $this->Note->findAll());
}
The method set is defined in Cake’s Controller
class, and is also inherited by AppController
, NotesController
and any other controller in your application. The purpose of set is to create a variable ($notes
) that will be available in your default view (index.thtml
), and its syntax is $this->set(string $variable_name, mixed $value)
.
The value of the $notes
variable is a multi-dimensional array returned by $this->Note->findAll()
. findAll
is a method defined in Cake’s Model
class, which fetches all records in the database table associated with the model. In this example, we’ll access our Note model and call the method from our controller.
Assuming that your notes table has some records, the output of findAll
will be something like this:
// print_r($notes) output:
Array
(
[0] => Array
(
[Note] => Array
(
[id] => 1
[title] => First note's title
[body] => Some text.
[created] => 2006-04-20 14:21:42
[modified] =>
)
)
[1] => Array
(
[Note] => Array
(
[id] => 2
[title] => Title...
[body] => body text
[created] => 2006-04-20 17:22:23
[modified] =>
)
)
)
As I mentioned before, this output is accomplished with only one line of code. CakePHP dramatically reduces the amount of repetitive and boring code required in your apps, thanks to its efficient built-in classes and intuitive conventions.
Creating our first view
We proceed similarly to view a single note. First, we need a view.thtml
view file in our /app/views/notes/
directory:
<h1><?php echo $data['Note']['title']?></h1>
<p><small>
Created: <?php echo $data['Note']['created']?>
</small></p>
<p><?php echo $data['Note']['body']?></p>
Then, we add the corresponding view action to our controller:
function view($id)
{
$this->Note->id = $id;
$this->set('data', $this->Note->read());
}
This method takes one parameter: the ID of the note we want to view ($id). In order to retrieve a particular note, we have to set the $id
variable of our Note
model to the $id
parameter we passed to the method. Then we create a $data
variable, which is available in our view via the set method. It contains an array returned by $this->Note->read()
. read
fetches only one row from our notes table, which corresponds to a particular $id
.
Adding, Editing and Deleting Notes
Next, we’ll create a view to add a new note. All we need is a file named add.thtml
in the /app/views/notes/
directory:
<h1>Add Note</h1>
<form action="<?php echo $html->url("/notes/add"); ?>" method="post">
<p>
Title:
<?php echo $html->input('Note/title', array('size' => '40'))?>
</p>
<p>
Body:
<?php echo $html->textarea('Note/body') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
<model_name>/<table_field>
.
The add
method for the Notes Controller can be something like this:
function add()
{
if (!empty($this->data['Note']))
{
if($this->Note->save($this->data['Note']))
{
$this->flash('Your note has been updated.','/notes/');
}
}
}
First of all we check whether or not the $this->data
variable — a sort of “optimized” version of the $_POST
array — is empty. If it contains something, that data is automatically saved in your notes table through the $this->Note->save()
method call.
The flash method that’s called afterwards will be familiar to anyone who has dabbled in Rails: it’s used to keep small amounts of data in between requests, such as error messages or warnings; in this case it displays a temporary message for a few seconds, then redirects the user to http://localhost/notes/
.
Note: The created and modified fields of our notes table are automatically populated with relevant data whenever a note is added or modified via the save method, so there’s no need to keep track of those actions manually. Pretty useful, hey?
At this point you should notice that something is wrong. The add.thtml
view and the add action described above are potentially very, very dangerous in their simplicity: there is no data validation whatsoever, so, at the moment, any kind of data entered by our users will be stored in our database without being filtered or checked. Cake has some built-in validation and input sanitizing mechanisms (which we’ll examine briefly in the next section), but we’ll keep things simple for now, as this is just a very elementary example to introduce CakePHP’s basic features.
Editing a note is similar to adding a new one, the difference being that the edit form’s values must already contain data.
/app/views/notes/edit.thtml:
<h1>Edit Note</h1>
<form action="<?php echo $html->url('/notes/edit')?>" method="post">
<?php echo $html->hidden('Note/id'); ?>
<p>
Title:
<?php echo $html->input('Note/title', array('size' => '40'))?>
</p>
<p>
Body:
<?php echo $html->textarea('Note/body') ?>
</p>
<p>
<?php echo $html->submit('Save') ?>
</p>
</form>
/app/controllers/notes_controller.php:
function edit($id = null)
{
if (empty($this->data['Note']))
{
$this->Note->id = $id;
$this->data = $this->Note->read();
}
else
{
if($this->Note->save($this->data['Note']))
{
$this->flash('Your note has been updated.','/notes/');
}
}
}
In this case, if no data is submitted, the values from the record we want to edit are retrieved and displayed in the view. Otherwise, if data is submitted, the record is updated via the save method as usual. Again, there are some obvious limitations to this simple function:
- We do not validate, filter or check the
$id
parameter (in reality, we should make sure that the$id
is numeric and that it actually exists). - Submitted data is not validated or filtered.
- No error handling occurs — if something goes wrong, the user will never receive a warning message.
- Finally, in order to delete a note, all we need to do is create a delete action in our
NotesController
; no view file is necessary, since users will be redirected to the index page, where a message will be displayed.
/app/controllers/notes_controller.php:
function delete($id)
{
if ($this->Note->del($id))
{
$this->flash('The note with id: '.$id.' has been deleted.', '/notes');
}
}
After defining all of our CRUD operations, we can make the interface easier to use by adding some convenient links for adding, editing and deleting notes. We can also rewrite our index.thtml
view using the HTML Helper:
<h1>My Notes</h1>
<p>
<?php echo $html->link('Add Note', '/notes/add') ?>
</p>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<?php foreach ($notes as $note): ?>
<tr>
<td><?php echo $note['Note']['id']; ?></td>
<td>
<?php echo $html->link($note['Note']['title'], "/notes/view/{$note['Note']['id']}")?>
[<?php echo $html->link('Edit', "/notes/edit/{$note['Note']['id']}")?>,
<?php echo $html->link('Delete', "/notes/delete/{$note['Note']['id']}", null, 'Are you sure?')?>]
</td>
<td><?php echo $note['Note']['created']; ?></td>
</tr>
<?php endforeach; ?>
</table>
In this example, I used the $html->link()
method call, which is able to easily create “Cake-friendly” links. It can take up to six parameters:
- the text of the link
- the internal URL
- an array of HTML attributes (if any)
- text for a Javascript confirmation message
- whether we want to convert special characters in the title to HTML entities
- whether this method should either return or output a value
link($title
,$url=null
,$htmlAttributes=null
,$confirmMessage=false
,$escapeTitle=true
,$return=false)
<?php
class NotesController extends AppController
{
var $name = 'Notes';
function index()
{
$this->set('notes', $this->Note->findAll());
}
function view($id)
{
$this->Note->id = $id;
$this->set('data', $this->Note->read());
}
function add()
{
if (!empty($this->data['Note']))
{
if($this->Note->save($this->data['Note']))
{
$this->flash('Your note has been updated.','/notes/');
}
}
}
function edit($id = null)
{
if (empty($this->data['Note']))
{
$this->Note->id = $id;
$this->data = $this->Note->read();
}
else
{
if($this->Note->save($this->data['Note']))
{
$this->flash('Your note has been updated.','/notes/');
}
}
}
function delete($id)
{
if ($this->Note->del($id))
{
$this->flash('The note with id: '.$id.' has been deleted.', '/notes');
}
}
}
?>
Not too difficult, is it? Granted, if you’re not accustomed to the MVC pattern, this might all seem a bit strange, but our PHP code definitely looks much more organized and it’s much easier to maintain than most unstructured PHP architectures.
One thing to keep in mind is that all those little conventions used in Cake actually matter: for example, the name of the controller must be plural and the model must be singular, while database tables should be plural (CakePHP’s Inflector class does the rest), views must be placed in a folder named after the controller, and so on. Yes, you can get around some of these conventions, but it is precisely these details that make Cake virtually self-configuring: it’s a case of convention over configuration, exactly like Rails. CakePHP may not be not the best solution for everybody, but it’s certainly a simple and intuitive way to solve many of the problems associated with web development.
At this point, you probably have a lot of questions. For example, I wrote that CakePHP has a native validation mechanism and it can sanitize data. What does that mean? Why didn’t we modify our model class? We’ll answer these and other questions in the next section.
FAQs about CakePHP’s Additional Features
CakePHP offers a lot of features that cannot properly be described in a single article. However, I’ve included a shortlist of frequently asked questions that may help you to understand this framework further. 1. How can I make my application more secure?<?php
class Note extends AppModel
{
var $name = 'Note';
var $validate = array(
'title' => VALID_NOT_EMPTY,
'body' => VALID_NOT_EMPTY
);
}
?>
After you define validation rules, all relevant actions and views should be modified accordingly. More information and examples are available in these pages of the manual. 2. Is there any way to turn off Cake’s ‘debugging mode’? Is there a main configuration file? Yes. A main configuration file, which governs some of CakePHP’s core settings, is located inVALID_NOT_EMPTY
is a constant defined in/cake/libs/validators.php
, and can be used to make sure that a particular field is not left blank. CakePHP comes with some predefined constants, but custom constants can be created.
/app/config/core.php
. Some of the settings that can be modified via this file include:
- CakePHP’s debugging verbosity and type
- logging level
- cookies and session duration
- session storage location
/app/
directory and create methods that will be available in all of your custom controllers that extend AppController. Even if you’re not planning to use an AppController at first, it’s often wise to create custom controllers which extend AppController rather than the Controller
class.
An easy way to create custom classes handling a specific task is to create a component. Components can be loaded automatically in controllers (and only inside controllers) by adding a variable named $components
:
var $components = array('Session', 'MyCustomComponent');
CakePHP comes with some default components such as Session, which offers convenient ways to organize session data, or RequestHandler, which can be used to determine more information about HTTP requests. These are documented in the CakePHP manual:
4. Does CakePHP require PHP5?
No. CakePHP is 100% compatible with PHP4. Personally, I think this is one of Cake’s main strengths. For example, the __construct()
method can be used on PHP4 on all classes extending the Object
core class, which is to say nearly everything in CakePHP. Similar patches have been included in the core libraries to offer additional functionality in PHP4 as well. Unfortunately, variables and methods don’t support access modifiers, and a private method should be prefixed with an underscore. This is not just a convention: in a controller, it really means that the method is private. If someone tries to access it (e.g. via http://localhost/notes/_privatemethod/
), Cake will return an error.
5. What are CakePHP’s default helpers?
CakePHP comes with some very handy helpers that can really make your life easier when it comes to creating views:
- HTML — allows quick creation of HTML tags, including links and input fields
- JavaScript — offers an easy way to manage JavaScript code
- Number — a set of useful methods to format numeric data
- Time — functions to format time strings and timestamps
- Text — auto-link URLs, truncate strings, create excerpts, highlight, strip links and more
- AJAX — a truly amazing AJAX helper, to be used in conjunction with the popular Prototype and script.aculo.us libraries; this helper can really speed up the creation of AJAX interfaces
/vendors/
directory and load it into your controller like this:
vendors('MyClassName');
If you need to define custom application-wide constants or functions, you can place them in /app/config/bootstrap.php
, which will make them available everywhere in your application.
You can adapt your code and create a helper or a component to be used in conjunction with views or controllers.
You can also try to integrate other software packages into Cake.
7. What if I need to work with more than one table simultaneously?
By default, a NotesController will try to locate and load a Note
model class. If your controller needs to access more than its default model, you can define additional models by setting the $uses
array, like this:
var $uses = array(Note, AnotherModel, YetAnotherModel);
In some cases, two or more tables might be closely related and would therefore be used with JOIN statements: your notes may have been submitted by different people listed in an authors table, for example. In these cases, CakePHP’s Associations can be used to define complex table relationships directly in your Model
class. More information is available in these manual pages.
8. Is it possible to further customize my application’s URLs?
Yes. Check out the /app/config/routes.php
file, and feel free to define or modify your custom routes. For example:
$Route->connect ('/', array('controller'=>'notes', 'action'=>'index'));
This creates a default route for http://localhost/
to:
http://localhost/notes/index/.
9. Is there an authentication mechanism in Cake?
Yes and no. There’s no official authentication component, simply because needs can be very different depending on the type of application being developed. There is, however, a built-in Access Control List mechanism involving flat files or databases. More information can be found in these manual pages.
CakePHP Resources
The CakePHP Project is continuously growing: as more and more users start using the framework and creating their own projects, the documentation continues to improve. As such, more and more web sites and blogs are developing a lot of useful information that they’re making freely available to CakePHP “bakers”. Here’s a shortlist of various places featuring Cake-related material: The official CakePHP site CakePHP Wiki — a community-powered wiki with various Cake tutorials and how-tos The CakePHP Manual — CakePHP’s official manual, which is still a work in progress, but already is fairly comprehensive CakePHP Google user group — a very lively user group; if you have a question to ask, go here Official CakePHP IRC channel: #cakephp on irc.freenode.net — chat with other bakers, as well as CakePHP’s creators, in real timeSummary
CakePHP is a mature framework for PHP developers who want the structure and time-saving benefits of Ruby on Rails, without having to leave their comfort zone or get their head around obscure Ruby syntax. Using Cake’s scaffolding, it’s possible to build a prototype application quickly, using a minimal amount of code. And, with a large number of helper classes available to extend and customize your application while retaining a sensible and easily maintainable architecture, Cake makes the possibilities endless. CakePHP is being actively developed, and is backed by extensive documentation and a lively support community. This article has given you a taste of what’s possible with CakePHP. Now it’s time for you to go off and do a little baking of your own!Frequently Asked Questions about Application Development with CakePHP
What is CakePHP and why is it used in application development?
CakePHP is an open-source web framework that follows the Model-View-Controller (MVC) approach. It is written in PHP and is designed to make building web applications simpler, faster, and require less code. It provides a foundational structure for programmers to create web applications. Its primary goal is to enable developers to work in a structured and rapid manner–without loss of flexibility.
How does CakePHP compare to other PHP frameworks?
CakePHP stands out from other PHP frameworks due to its ease of use, speed, and security. It provides a comprehensive set of libraries for commonly needed tasks, as well as a simple interface and logical structure to access these libraries. CakePHP has built-in tools for input validation, CSRF protection, Form tampering protection, SQL injection prevention, and XSS prevention, making it a secure choice for developers.
What are the key features of CakePHP?
CakePHP comes with a host of features that make it a go-to choice for developers. Some of these include MVC architecture, ORM (Object Relational Mapping), Zero configuration, Code generation, and scaffolding, among others. These features allow developers to easily manage and manipulate data, create, read, update and delete (CRUD) operations, and generate code quickly and efficiently.
How can I install CakePHP?
CakePHP can be installed using Composer, a tool for dependency management in PHP. You can download Composer and follow the instructions to install CakePHP. Once installed, you can start building your application.
What is the MVC pattern in CakePHP?
MVC stands for Model, View, and Controller. It is a design pattern that separates an application into three main logical components. The Model represents the application data and business rules, the View represents the output or presentation layer, and the Controller handles the input and coordinates the Model and View.
How does CakePHP handle database access?
CakePHP uses the ORM technique for database access. This means that it represents data and relationships using PHP classes. These classes can be used to interact with your database as if they were persistent objects.
What is scaffolding in CakePHP?
Scaffolding is a technique used in CakePHP that allows developers to define and create a basic application that can create, retrieve, update and delete objects.
How does CakePHP handle security?
CakePHP comes with built-in tools for input validation, CSRF protection, Form tampering protection, SQL injection prevention, and XSS prevention. This makes it a secure choice for developers.
Can I use CakePHP for commercial applications?
Yes, CakePHP is licensed under the MIT license which makes it perfect for use in commercial applications.
Where can I find more resources to learn CakePHP?
There are many resources available online to learn CakePHP. The official CakePHP website provides a comprehensive guide and API documentation. Other resources include online tutorials, blogs, and forums.
Fabio just started working as technical writer for Siemens Italia. He's also very fond of PHP programming and enjoys writing and blogging about it on his personal web site, H3RALD.com.