 | 使用 Bake 代码生成器
没必要完全抛弃 Scaffolding 提供的全部内容。通过使用 Bake(CakePHP 代码生成器),可以生成一个包含 Scaffolding 功能和相关视图的控制器。对于 Tor 中与产品相关的部分,这将是一个节省大量时间的方法。
在 CakePHP V1.1 中,Bake 是一个直接调用的 PHP 脚本。在 CakePHP V1.2 中,Bake 功能已经转移到了 Cake Console 中,在本教程后面您会逐渐熟悉 Cake Console。将路径 /webroot/cake/console 添加到环境的 PATH 变量中,可以简化操作。设置这个变量之后,就可以直接调用 Cake Console 而不需要指定路径信息。这种做法并不是必需的,本教程假设不这样做。另外,应该从应用程序的 app 目录(在本示例中是 /webroot/app)运行 Cake Console,否则 Cake Console 会认为您打算对新的应用程序执行操作。
在继续执行操作之前,请制作现有 app 目录的拷贝。Bake 将覆盖 products 控制器,而且当操作包括关键字 “overwrite”(或者 “copy”、“delete”、“format” 或 “voodoo”)时,应当经常备份文件。如果遇到问题,请确保 php 位于环境的 PATH 变量中。
对 products 控制器使用 Bake
要想使用 Bake,应该使用 cd 命令切换到 /webroot/app 目录并启动 Cake Console:../cake/console/cake bake。您应当会看到一个与图 2 相似的屏幕。
图 2. Bake 菜单
对于 Tor 应用程序,已编写的模型应当不会有问题,所以让我们开始编写控制器。按 C 键选择控制器。Cake Console 将查看目前操作的应用程序,并列出可以运行 Bake 的控制器。
图 3. 控制器名称
在这个示例中,我们要对 products 控制器运行 Bake,它的控制器编号应该是 2。Bake 将询问您是否希望以交互方式构建控制器。目前,按 N 键让 Bake 自己做出所有决定,但是稍后您应当尝试以交互方式构建一个控制器,感受一下 Bake 的其他功能。接下来,Bake 会询问是否希望包含一些基本的类方法(见图 4)。按 Y(因为我们使用 Bake 的目的就是获得这些代码)。接下来,Bake 会询问是否希望创建用于管理路由的方法。按 N(目前不需要这些方法)。Bake 应当会通知您它创建了文件 \app\controllers\products_controller.php,并询问是否希望创建一些单元测试文件。目前可以跳过它们。完成操作之后,会回到 Bake 菜单。
图 4. 已创建的控制器
大功告成!退出 Cake Console,打开 app/controllers/products_controller.php,看看 Bake 为您实现了什么功能。它应当类似于清单 8。
清单 8. 运行 Bake 后的 products_controller.php
class ProductsController extends AppController {
var $name = 'Products';
var $helpers = array('Html', 'Form' );
function index() {
$this->Product->recursive = 0;
$this->set('products', $this->paginate());
}
function view($id = null) {
if (!$id) {
$this->Session->setFlash('Invalid Product.');
$this->redirect(array('action'=>'index'), null, true);
}
$this->set('product', $this->Product->read(null, $id));
}
function add() {
if (!empty($this->data)) {
$this->cleanUpFields();
$this->Product->create();
if ($this->Product->save($this->data)) {
$this->Session->setFlash('The Product has been saved');
$this->redirect(array('action'=>'index'), null, true);
} else {
$this->Session->setFlash('The Product could not be
saved. Please, try again.');
}
}
$dealers = $this->Product->Dealer->generateList();
$this->set(compact('dealers'));
}
function edit($id = null) {
if (!$id && empty($this->data)) {
$this->Session->setFlash('Invalid Product');
$this->redirect(array('action'=>'index'), null, true);
}
if (!empty($this->data)) {
$this->cleanUpFields();
if ($this->Product->save($this->data)) {
$this->Session->setFlash('The Product has been saved');
$this->redirect(array('action'=>'index'), null, true);
} else {
$this->Session->setFlash('The Product could not be
saved. Please, try again.');
}
}
if (empty($this->data)) {
$this->data = $this->Product->read(null, $id);
}
$dealers = $this->Product->Dealer->generateList();
$this->set(compact('dealers'));
}
function delete($id = null) {
if (!$id) {
$this->Session->setFlash('Invalid id for Product');
$this->redirect(array('action'=>'index'), null, true);
}
if ($this->Product->del($id)) {
$this->Session->setFlash('Product #'.$id.' deleted');
$this->redirect(array('action'=>'index'), null, true);
}
}
}
?>
|
使用 Cake Console 生成的这个控制器包含的基本功能与通过 Scaffolding 生成的控制器相同,但是现在可以根据需要做出调整。十分方便!准备好继续了吗?
对 products 视图使用 Bake
现在已经对 products 控制器运行了 Bake,Tor 还需要一些产品视图。Bake 也将替您执行这些操作。像以前一样,在 /webroot/app 目录中执行 ../cake/console/cake bake。
最初的 Bake 菜单应当与对控制器运行 Bake 时一样。不过,这一次要生成一些视图。按 V 键选择视图。系统将列出可以运行 Bake 的视图列表。products 仍然应该位于列表中的第二位。Bake 将询问是否希望以交互方式构建视图。目前,按 N 键让 Bake 自己做出所有决定。Bake 还会询问是否希望生成用于管理路由的视图。目前也跳过它们。您以后可以试试交互式 Bake 和管理路由选项。
跳过这两个选项之后,Bake 应当会通知您它已经创建了视图。
图 5. Bake 通知您它已经创建了视图
退出 Cake Console 并打开 app/views/products/index.ctp 视图。它应当类似于清单 9。
清单 9. index 视图
<div class="products">
<h2><?php __('Products');?></h2>
<p>
<?php
echo $paginator->counter(array(
'format' => __('Page %page% of %pages%, showing %current%
records out of %count% total, starting on record %start%, ending on %end%', true)
));
?></p>
<table cellpadding="0" cellspacing="0">
<tr>
<th><?php echo $paginator->sort('id');?></th>
<th><?php echo $paginator->sort('title');?></th>
<th><?php echo $paginator->sort('dealer_id');?></th>
<th><?php echo $paginator->sort('description');?></th>
<th class="actions"><?php __('Actions');?></th>
</tr>
<?php
$i = 0;
foreach ($products as $product):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="altrow"';
}
?>
<tr<?php echo $class;?>>
<td>
<?php echo $product['Product']['id'] ?>
</td>
<td>
<?php echo $product['Product']['title'] ?>
</td>
<td>
<?php echo $html->link(__($product['Dealer']
['title'], true), array('controller'=> 'dealers', '
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
action'=>'view', $product['Dealer']['id'])); ?>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
</td>
<td>
<?php echo $product['Product']['description'] ?>
</td>
<td class="actions">
<?php echo $html->link(__('View', true),
array('action'=>'view', $product['Product']['id'])); ?>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
<?php echo $html->link(__('Edit', true),
array('action'=>'edit', $product['Product']['id'])); ?>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
<?php echo $html->link(__('Delete', true),
array('action'=>'delete', $product['Product']['id']),
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
null, sprintf(__('Are you sure you want to delete
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
#%s?', true),
$product['Product']['id'])); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
<div class="paging">
<?php echo $paginator->prev('<< '.__('previous', true),
array(), null, array('class'=>'disabled'));?>
| <?php echo $paginator->numbers();?>
<?php echo $paginator->next(__('next', true).' >>',
array(), null, array('class'=>'disabled'));?>
</div>
<div class="actions">
<ul>
<li><?php echo $html->link(sprintf(__('New %s', true),
__('Product', true)), array('action'=>'add')); ?></li>
<li><?php echo $html->link(sprintf(__('List %s', true),
__('Dealers', true)), array('controller'=> 'dealers',
'action'=>'index')); ?> </li>
<li><?php echo $html->link(sprintf(__('New %s', true),
__('Dealer', true)), array('controller'=> 'dealers',
'action'=>'add')); ?> </li>
</ul>
</div>
|
再看看其他视图。这节省了大量必要的代码编写工作。稍后,将调整这些视图以帮助改进 Tor。
测试
已经用 Bake 为产品功能生成了一个控制器和必要的视图。现在让应用程序运转起来。访问 http://localhost/products 并浏览应用程序的各个部分。添加产品,编辑一个产品,删除另一个产品,查看产品。它看上去应当与使用 Scaffolding 时的表现完全相同。
通过 Bake 生成更大更好的应用程序
这些并不是 Bake 能实现的所有功能。本教程末尾将有几个练习,让您可以尝试自己的更多想法。请记住,Bake 所生成的代码仅仅是一个起点,而不是开发工作的终结。但是如果正确使用,它能显著地节省时间。
|  |