创建数据库
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,
`updated` 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,
`updated` 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,
`updated` 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());
app/models/title.php 中的模型类支持新的 $hasOne 属性,此属性用于指出与本模型类相关联的其他模型类。
<?php
class Title extends AppModel
{
var $hasOne = 'publisher,category';
/**
* 译者注:实际上现在的版本与当时的 Revision [345] 版本已经有所不同,
* $hasOne 表示的是一对一关系,而在这个例子中,图书标题和出版商、图书分类的关系是“多对一”,
* 即多本书可同属于一个出版商,可同属于一个类,所以不应该使用 $hasOne,而应使用 $belongsTo。
* 如果您使用的是最新版本的话,请将上边的代码改为:
* var $belongsTo = 'publisher,category';
*/
}
?>
对于 Publisher(出版商)与 Category(图书类别)模型类,我们只需创建空的模型类即可。
app/models/publisher.php
<?php
class Publisher extends AppModel
{
}
?>
app/models/category.php
<?php
class Category extends AppModel
{
}
?>
现在增加一个 TitlesHelper 类以开始我们的控制器。当控制器类过于拥挤的时候,我们通常可以将方法移到相应的 helper 类中。现在,这个 helper 类是空的。
app/helpers/titles_helper.php
<?php
class TitlesHelper extends AppController
{
}
?>
接下来是控制器,第一眼看到的是如何使用 set 方法。
在 add() 方法中,两个本地变量($cats 与 $pubs)作为数组,被写入数据,最后供视图(view)使用,此过程(供视图使用的过程)实际上是通过 set() 方法实现的。
set() 的奇妙功用在 edit() 方法中亦有体现。
app/controllers/titles_controller.php
<?php
class TitlesController extends TitlesHelper
{
function index()
{
$this->set('data', $this->models['title']->findAll());
}
function view($id)
{
$this->set('data', $this->models['title']->read());
}
function add()
{
foreach ($this->models['title']->category->findAll() as $pass)
{
foreach ($pass as $key => $value)
{
$cats[$value['id']] = $value['name'];
}
}
foreach ($this->models['title']->publisher->findAll() as $pass)
{
foreach ($pass as $key => $value)
{
$pubs[$value['id']] = $value['name'];
}
}
$this->set('cats', $cats);
$this->set('pubs', $pubs);
if(empty($this->params['data']))
{
$this->render();
}
else
{
if($this->models['title']->save($this->params['data']))
{
$this->flash('Your title has been saved.','/titles');
}
else
{
$this->set('data', $this->params['data']);
$this->validateErrors($this->models['title']);
$this->render();
}
}
}
function delete($id)
{
if ($this->models['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->models['title']->read();
$data = $this->params['data'];
foreach ($this->models['title']->category->findAll() as $pass)
{
foreach ($pass as $key => $value)
{
$cats[$value['id']] = $value['name'];
if ($value['id'] === $data['title']['category_id'])
{
$catselected = $value['id'];
}
}
}
foreach ($this->models['title']->publisher->findAll() as $pass)
{
foreach ($pass as $key => $value)
{
$pubs[$value['id']] = $value['name'];
if ($value['id'] === $data['title']['publisher_id'])
{
$pubselected = $value['id'];
}
}
}
$this->set('cats', $cats);
$this->set('catselected', $catselected);
$this->set('pubs', $pubs);
$this->set('pubselected', $pubselected);
$this->render();
}
else
{
$this->models['title']->set($this->params['data']);
if ( $this->models['title']->save())
{
$this->flash('The title has been updated.','/titles');
}
else
{
$this->set('data', $this->params['data']);
$this->validateErrors($this->models['title']);
$this->render();
}
}
}
}
?>
旧时的 Cake 用户:现在 index 方法已经修改了很多地方。代码已经可以缩减为一行了,例如以前这样的代码:
<?php
function view ( $id )
{
$this->title->setId( $id );
$this->set('data', $this->title->read());
}
?>
现在缩减为一行:
<?php
function view($id)
{
$this->set('data', $this->models['title']->read());
}
?>
好的!让我们继续视图部分!
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->linkTo($output['title']['title'], "/titles/view/{$output['title']['id']}/{$output['publisher']['id']}/{$output['category']['id']}")?>
<?php echo $html->linkTo('Delete',"/titles/delete/{$output['title']['id']}/{$output['publisher']['id']}/{$output['category']['id']}")?>
<?php echo $html->linkTo('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->linkTo('Edit',"/categories/edit/{$output['category']['id']}")?></td>
</td>
<td>
<?php echo $output['title']['price']?>
</td>
<td>
<?php echo $output['publisher']['name']?>
<?php // not implemented echo $html->linkTo('Edit',"/publishers/edit/{$output['publisher']['id']}")?></td>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td colspan="3">
<?php echo $html->linkTo('Add a new Book Title', '/titles/add') ?>
</td>
</tr>
</table>
注意:所有的信息都存放在 $data 数组中,而各个模型类则是以模型名为键值的子数组,模型的属性也都存放在各自对应的子数组中。如 $data['title']['price'] 为 Title 模型类的 price 属性。
app/views/titles/add.thtml
<h2>Add Title</h2>
<?php echo $html->formTag('/titles/add')?>
<p>SKU: <?php echo $html->inputTag('title/id', 80)?>
<?php //echo $html->tagErrorMsg('title/id', 'Sku is required.') ?>
</p>
<p>Title: <?php echo $html->inputTag('title/title', 80)?>
<?php //echo $html->tagErrorMsg('title/title', 'Title is required.') ?>
</p>
<p>Price: <?php echo $html->inputTag('title/price', 40)?>
<?php //echo $html->tagErrorMsg('title/price', 'price is required.') ?>
</p>
<p>Category: <?php echo $html->selectTag('title/category_id', $cats)?>
</p>
<p>Publisher: <?php echo $html->selectTag('title/publisher_id', $pubs)?>
</p>
<p><?php echo $html->submitTag('Save') ?>
</p>
</form>
app/views/titles/edit.thtml
<h2>Edit Title</h2>
<?php echo $html->formTag('/titles/edit')?>
<?php echo $html->hiddenTag('title/id')?>
<p>Title: <?php echo $html->inputTag('title/title', 80)?>
<?php echo $html->tagErrorMsg('title/title', 'Title is required.') ?>
</p>
<p>Price: <?php echo $html->inputTag('title/price', 40)?>
<?php echo $html->tagErrorMsg('title/price', 'price is required.') ?>
</p>
<p>Category: <?php echo $html->selectTag('title/category_id', $cats, $catselected)?>
</p>
<p>Publisher: <?php echo $html->selectTag('title/publisher_id', $pubs, $pubselected)?>
</p>
<p><?php echo $html->submitTag('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>
正如你所看到的,$data 现在是多维数组了:我们在视图中包含的每一个表都对应于它们的子数组(这是使用 $hasOne 进行关联的,还记得吗?),这些子数组的元素包括了表的各个字段。