Table of Contents

Cake Tutorial: Books Title Example (With hasOne)

This tutorial shows a little bit about using Cake’s automatic associations.

Requires

RC5 ready- gwoo

Create database

Here’s the SQL:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(250) NOT NULL DEFAULT '',
  `parent_id` int(11) NOT NULL DEFAULT '0',
  `created` DATETIME DEFAULT NULL,
  `modified` DATETIME DEFAULT NULL,
  PRIMARY KEY  (`id`)
);
 
INSERT INTO `categories` (`id`, `name`, `parent_id`, `created`) VALUES (1, 'Business', 0, NOW());
INSERT INTO `categories` (`id`, `name`, `parent_id`, `created`) VALUES (2, 'Modern Cookbook', 0, NOW());
INSERT INTO `categories` (`id`, `name`, `parent_id`, `created`) VALUES (3, 'Popular Computing', 0, NOW());
INSERT INTO `categories` (`id`, `name`, `parent_id`, `created`) VALUES (4, 'Psychology', 0, NOW());
INSERT INTO `categories` (`id`, `name`, `parent_id`, `created`) VALUES (5, 'Undecided', 0, NOW());
 
CREATE TABLE `publishers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(250) NOT NULL DEFAULT '',
  `created` DATETIME DEFAULT NULL,
  `modified` DATETIME DEFAULT NULL,
  PRIMARY KEY  (`id`)
);
 
 
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (1, 'New Moon Books', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (2, 'Binnet & Hardley', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (3, 'Algodata Infosystems', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (4, 'Five Lakes Publishing', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (5, 'Ramona Publishers', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (6, 'GGG&G', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (7, 'Scootney Books', NOW());
INSERT INTO `publishers` (`id`, `name`, `created`) VALUES (8, 'Lucerne Publishing', NOW());
 
CREATE TABLE `titles` (
  `id` varchar(250) NOT NULL DEFAULT '',
  `title` varchar(250) NOT NULL DEFAULT '',
  `category_id` int(11) NOT NULL DEFAULT '0',
  `price` decimal(19,8) NOT NULL DEFAULT '0.00000000',
  `publisher_id` int(11) NOT NULL DEFAULT '0',
  `created` DATETIME DEFAULT NULL,
  `modified` DATETIME DEFAULT NULL,
  PRIMARY KEY  (`id`)
);
 
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('BU1032', 'The Busy Executives Database Guide', 1, 19.99000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('BU1111', 'Cooking with Computers', 1, 11.95000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('BU2075', 'You Can Combat Computer Stress', 1, 2.99000000, 1, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('BU7832', 'Straight Talk About Computers', 2, 19.99000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('MC2222', 'Silicon Valley Gastronmic Treats', 2, 19.99000000, 2, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('MC3021', 'The Gourmet Microwave', 2, 2.99000000, 2, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('MC3026', 'The Psychology of Computer Cooking', 5, 9.99000000, 2, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('PC1035', 'But Is It User Friendly', 3, 22.95000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('PC8888', 'Secrets Of Silicon Valley', 3, 20.99000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('PC9999', 'Net Etiquette', 3, 5.99000000, 3, NOW());
INSERT INTO `titles` (`id`, `title`, `category_id`, `price`, `publisher_id`, `created`) VALUES ('PS2091', 'Is Anger the Enemy', 4, 10.95000000, 1, NOW());

Create Models

The model in app/models/title.php sports the new $belongsTo property, which notes what associations this model has.

<?php
 
   class Title extends AppModel
   {
      var $name = 'Title'; // required for php4 installs
      var $belongsTo = 'Category,Publisher';
   }
?>

And we just start with empty models for Publisher and Category.

app/models/publisher.php

<?php
 
   class Publisher extends AppModel
   {
      var $name = 'Publisher'; // required for php4 installs
      var $hasMany = 'Title';
   }
?>

app/models/category.php

<?php
 
   class Category extends AppModel
   {
      var $name = 'Category'; // required for php4 installs
      var $hasMany = 'Title';
   }
?>

Create Controllers

Note how set() methods are used in the add() method; two local variables ($cats and $pubs) are filled with data in array shape for use in the view; afterwards, these are set() to actually be passed on.

The set() approach is also used in the edit() method.

app/controllers/titles_controller.php

<?php
 
   class TitlesController extends AppController
   {
      var $name = 'Titles'; // required for PHP4 installs
      function index()
      {
         $this->set('data', $this->Title->findAll());
      }
   
      function view($id)
      {
         $this->set('data', $this->Title->read());
      }
      
      function add()
      {
		  
	 $this->set('cats', $this->Title->Category->generateList());
	 $this->set('pubs', $this->Title->Publisher->generateList());
         
         if(empty($this->params['data']))  
         {
            $this->render();
         }
         else
         {
            if($this->Title->save($this->params['data'])) 
            {
               $this->flash('Your title has been saved.','/titles');
            }
            else
            {
               $this->render();
            }
         }
      }
   
      function delete($id)
      {
         if ($this->Title->del($id)){
            $this->flash('The title with id: '.$id.' has been deleted.', '/titles');
         }
      }
      
      function edit($id=null)
      {
         if (empty($this->params['data']))
         {
            $this->params['data'] = $this->Title->read();
 
            $this->set('cats', $this->Title->Category->generateList());
	    $this->set('pubs', $this->Title->Publisher->generateList());
 
            $this->render();
         }
         else
         {
            if ( $this->Title->save($this->params['data']))
            {
               $this->flash('The title has been updated.','/titles');
            }
            else
            {
 
               $this->render();
            }
         }
      }
   }
?>

and the beginning of app/controllers/categories_controller.php

<?php
class CategoriesController extends AppController
{
    var $name='Categories';
}
?>

and app/controllers/publishers_controller.php

<?php
class PublishersController extends AppController
{
    var $name='Publishers';
}
?>

Create Views

Great! Let’s create a table View - to display the, above, controller $data!

app/views/titles/index.thtml

<h1>Titles</h1>
   <table>
         <tr>
            <th>Id</th>
            <th>Title</th>
            <th>Category</th>
            <th>Price</th>
            <th>Publisher</th>
         </tr>
<?php foreach ($data as $output): ?>
        <tr>
            <td>
               <?php echo $output['Title']['id']?>
            </td>
            <td>
               <?php echo $html->link($output['Title']['title'], "/titles/view/{$output['Title']['id']}/{$output['Publisher']['id']}/{$output['Category']['id']}")?>
               <?php echo $html->link('Delete',"/titles/delete/{$output['Title']['id']}/{$output['Publisher']['id']}/{$output['Category']['id']}"); ?>
               <?php echo $html->link('Edit',"/titles/edit/{$output['Title']['id']}/{$output['Publisher']['id']}/{$output['Category']['id']}")?></td>
            </td>
            <td>
               <?php echo $output['Category']['name']?>
               <?php // not implemented echo $html->link('Edit',"/categories/edit/{$output['Category']['id']}")?></td>
            </td>
            <td>
               <?php //echo $output['Title']['price']; ?>
               <?php echo number_format($output['Title']['price'],2); ?>
            </td>
            <td>
               <?php echo $output['Publisher']['name']; ?>
               <?php // not implemented echo $html->link('Edit',"/publishers/edit/{$output['Publisher']['id']}")?></td>
            </td>
         </tr>
<?php endforeach; ?>
         <tr>
            <td colspan="3">
               <?php echo $html->link('Add a new Book Title', '/titles/add') ?>
            </td>
         </tr>
   </table>

Change notice: Note that all the information in $data is put into an array where the model name is a sub-array which holds an array with its properties. $data[’Title’][’price’] for instance.

Change notice: number_format() added to price display for readability in output - dingonv

app/views/titles/add.thtml

<h2>Add Title</h2>
 
<?php echo $html->formTag('/titles/add')?>
    <p>SKU: <?php echo $html->input('Title/id'); ?>
             <?php //echo $html->tagErrorMsg('Title/id', 'Sku is required.');  ?>
   </p>
    <p>Title: <?php echo $html->input('Title/title'); ?>
              <?php //echo $html->tagErrorMsg('Title/title', 'Title is required.');  ?>
    </p>
    <p>Price: <?php echo $html->input('Title/price'); ?>
              <?php //echo $html->tagErrorMsg('Title/price', 'price is required.');  ?>
    </p>
    <p>Category: <?php echo $html->selectTag('Title/category_id', $cats,$html->tagValue('Title/category_id')); ?>
    </p>
    <p>Publisher: <?php echo $html->selectTag('Title/publisher_id', $pubs, $html->tagValue('Title/publisher_id')); ?>
    </p>
    <p><?php echo $html->submit('Save');  ?>
    </p>
 
</form>

app/views/titles/edit.thtml

<h2>Edit Title</h2>
 
<?php echo $html->formTag('/titles/edit'); ?>
<?php echo $html->hidden('Title/id'); ?>
    <p>Title: <?php echo $html->input('Title/title'); ?>
              <?php echo $html->tagErrorMsg('Title/title', 'Title is required.');  ?>
    </p>
    <p>Price: <?php echo $html->input('Title/price'); ?>
              <?php echo $html->tagErrorMsg('Title/price', 'price is required.');  ?>
    </p>
    <p>Category: <?php echo $html->selectTag('Title/category_id', $cats, $html->tagValue('Title/category_id')); ?>
    </p>
    <p>Publisher: <?php echo $html->selectTag('Title/publisher_id', $pubs, $html->tagValue('Title/publisher_id')); ?>
    </p>
    <p><?php echo $html->submit('Save');  ?></p>
 
</form>

app/views/titles/view.thtml

<h1><?php echo $data['Title']['title']; ?></h1>
<p><small>Cost: <?php echo $data['Title']['price']; ?></small></p>
<p><small>Publisher: <?php echo $data['Publisher']['name']; ?></small></p>
<p><small>Category: <?php echo $data['Category']['name']; ?></small></p>

As you can see, the $data array has an added dimension now. Each view table (using the model $hasOne association) has its own sub-arrays with table field elements.

(Will update more at a later date.)

 
tutorials/book_titles.txt · Last modified: 2006/02/24 04:11 by trooper