Adding and editing records
While listing and viewing records is handy, the ability to create and edit records allows you to build up and maintain your data.
In this recipe, we'll create actions to both add new products and edit the existing ones in our database.
Getting ready
For this recipe, we'll continue using the products
table from the previous recipe. We'll also extend the ProductsController
that was created.
For the views, we'll add add.ctp
and edit.ctp
files to our app/View/Products/
directory, and also a form.ctp
file in the Products/
directory that we'll create in app/View/Elements/
.
How to do it...
Perform the following steps:
- Add the following
add()
method to theProductsController
class:public function add() { if ($this->request->is('post')) { $this->Product->create(); if ($this->Product->save($this->request->data)) { $this->Session->setFlash(__('New product created')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Could not create product')); } }
- Just below the
add()
method, also add anedit()
method:public function edit($id) { $product = $this->Product->findById($id); if (!$product) { throw new NotFoundException(__('Product not found')); } if ($this->request->is('post')) { $this->Product->id = $id; if ($this->Product->save($this->request->data)) { $this->Session->setFlash(__('Product updated')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Could not update product')); } else { $this->request->data = $product; } }
- Introduce the following content in the
form.ctp
element file:<?php echo $this->Form->create('Product'); echo $this->Form->inputs(); echo $this->Form->end(__('Submit'));
- Introduce the following content in the
add.ctp
file:<?php echo $this->element('Products/form'); ?>
- The
edit.ctp
file will also take the same content, but the header text will be changed to the following code:<?php echo $this->element('Products/form'); ?>
- Return to the
index.ctp
file, and change it's content to the following:<h2><?php echo __('Products'); ?></h2> <div> <?php echo $this->Html->link(__('Add new product'), array('action' => 'add')); ?> </div> <table> <tr> <th><?php echo $this->Paginator->sort('id'); ?></th> <th><?php echo $this->Paginator->sort('name'); ?></th> <th><?php echo $this->Paginator->sort('created'); ?></th> <th><?php echo __('Actions'); ?></th> </tr> <?php foreach ($products as $product): ?> <tr> <td><?php echo $product['Product']['id']; ?></td> <td><?php echo $this->Html->link($product['Product']['name'], array('action' => 'view', $product['Product']['id'])); ?></td> <td><?php echo $this->Time->nice($product['Product']['created']); ?></td> <td><?php echo $this->Html->link(__('Edit'), array('action' => 'edit', $product['Product']['id'])); ?></td> </tr> <?php endforeach; ?> </table> <div> <?php echo $this->Paginator->counter(array('format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}'))); ?> </div> <div> <?php echo $this->Paginator->prev(__('< previous'), array(), null, array('class' => 'prev disabled')); echo $this->Paginator->numbers(array('separator' => '')); echo $this->Paginator->next(__('next >'), array(), null, array('class' => 'next disabled')); ?> </div>
- Navigate to
/products
in your web browser, and click one of the Edit links to modify a product. The following screenshot shows the screen that will appear: - Return to
/products
, and click on the Add new product link to create a new product. The following screenshot shows the screen that will appear:
How it works...
Here, we extended our previous recipe by adding some extra methods to create new products and edit the existing ones. The add()
method first checks whether the current request has been made using the HTTP POST
method. If that's the case, we call the create()
method on the Product
model. This doesn't create a new record yet, but instead it prepares our model object for a new record to be created. We then call the save()
method, passing the data provided in the request to it. The framework handles this internally through the Form
helper, which we'll see in a moment. The condition checks whether the save is successful (here, a new record is created), and if so, it calls the setFlash()
method on our Session
component to register a success message to be displayed on the page that follows. We do the same in the event that the record could not be saved, and it provided a failure message. We then wrap up the method by redirecting the request to our index()
action.
For the edit()
method, we first check that the product for the given ID actually exists using the findById()
method on the Product
model. See the previous recipe, Listing and viewing records, for details on finding records. If the product doesn't exist, a NotFoundException
is thrown; this is rendered as an error page. As with the add()
method, we first check that the request was made via POST
. However, instead of calling the create()
method on our Product
model, we set the $id
property with the $id
argument passed to our action. We then follow the same process of calling the save()
method with the request data, as well as setting the result messages for the view and redirecting the request.
We finalize our edit action by populating the request data if it does not exist so that when you visit the form for editing, it's populated with the existing values from the products
table.
For our views, we've taken the initiative to use an element. These are reusable sections of our views, which allow us to segment and organize our visual interface and cut down on duplicate code. Here, we've done this to avoid declaring the same form twice and reuse the same one instead. The framework is able to distinguish between the two (adding a record and editing a record) by the presence of an ID. In which case, it assumes that we're editing a record instead of creating one. In this file, we use the Form
helper to generate a new form using the create()
method and passing the name of the model to it, it will act against. We also called the inputs()
method to create the required inputs based on the table schema and then called the end()
method to complete the form.
For our add.ctp
and edit.ctp
view files, we included our element using the element()
method, passing it the location of our form.ctp
file. You'll notice that we created our element in the Products/
directory, as the form is intended for a product. We could change the contents of our element to receive the model name via an element parameter, making it more dynamic and, therefore, reusable even further. Finally, we updated the index.ctp
view to include an Edit option using the link()
method from the Html
helper.
You'll also see that we passed the ID of each product to this method in our foreach()
statement, thus generating a link for each product with its unique ID as part of the URL. We also added a link to "add a new product", which redirects you to the new add()
action to create a new record in the products
table.
See also
- You can read more on working with the session in CakePHP at http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html
- More details on saving data in Models can be found at http://book.cakephp.org/2.0/en/models/saving-your-data.html
- For a complete overview of the Form helper in CakePHP, go to http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
- The
Html
helper in CakePHP will become a common tool used in all of your views; read more about it at http://book.cakephp.org/2.0/en/core-libraries/helpers/html.html - The Listing and viewing records recipe