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>
This code creates a basic form that allows users to enter a title and text for a note, and to save it. This time, I decided to use some convenience code to create the two input tags via the so-called HTML Helper. Helpers will be discussed in detail in the next section of this article, but to be brief, they are classes that are accessible from views, and they contain useful methods for formatting text, creating tags, adding Javascript or AJAX code, and so on. The HTML Helper is available by default in all views, and is used to create (X)HTML tags. I used it in this view to create an input tag, a textarea and a submit button. The syntax is relatively straightforward, but it's important to note that in order to map the input fields to our table columns easily, and thus automate the insertion process, the names of the input fields (usually the first parameter of each method of the HTML Helper) must be in the 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)
The customized index page
The complete controller should look like this:
<?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?
The examples in this article are inherently insecure. Luckily, CakePHP comes with a Sanitize class, which can be used in Cake applications to filter strings or arrays to make them safe for display or insertion into the database.
More information about sanitizing can be found in the CakePHP manual.
Regarding validation, it's possible to make sure that the entered data satisfies particular rules or patterns by adding some validation rules to our model, like this:
<?php
class Note extends AppModel
{
var $name = 'Note';
var $validate = array(
'title' => VALID_NOT_EMPTY,
'body' => VALID_NOT_EMPTY
);
}
?>
VALID_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.
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 in /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
3. All the business logic should go in my controllers, but what if I want to re-use something elsewhere?
Good question. You will almost always have to create some complex logic for an application, and you usually want to re-use part of that logic. The most common way to include an application-wide function or variable so that it's available in every controller is to define it in your AppController file. This file basically consists of an empty class that extends Cake's internal Controller class, and is located in the /cake/ directory. You can move it to your /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:
Session component manual pages
Request Handler component manual pages
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
More information about helpers is available in the CakePHP manual.
6. Is there any way to include my custom function/class in Cake?
Sure there is. If you want to use a custom external class, you can put it in the /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. An example? Check out the CakeAMFPHP project.
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.
Source:
http://www.sitepoint.com/artic...-cakephp/2