Book Image

CakePHP 2 Application Cookbook

Book Image

CakePHP 2 Application Cookbook

Overview of this book

Table of Contents (20 chapters)
CakePHP 2 Application Cookbook
Credits
Foreword
About the Authors
About the Reviewer
www.PacktPub.com
Preface
Index

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:

  1. Add the following add() method to the ProductsController 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'));
      }
    }
  2. Just below the add() method, also add an edit() 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;
      }
    }
  3. 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'));
  4. Introduce the following content in the add.ctp file:

    <?php echo $this->element('Products/form'); ?>
  5. 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'); ?>
  6. 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>
  7. 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:

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