接上页:
var $hasOne = array('association1' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'this order by',
'dependent' => true,
'foreignKey' => 'foreign key'),
'association2' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'this order by',
'dependent' => true,
'foreignKey' => 'foreign key'),
'association3' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'this order by',
'dependent' => true,
'foreignKey' => 'foreign key'));
/**
* @var mixed $hasMany this can be a string or an array.
*
* Example below is using an array and setting more than one hasMany.
*
* Using hasMany as an array gives you more control over the association
*
* association - Table holding the association
* className - Specify the class name of the association.
* Use it only if that name can not be inferred from the association
name.
* So
* [code]
* var $hasMany = array(array('products'));
* [/code]
* will by default be linked to the Product class, but if the real
class name is SpecialProduct, you'll have to specify it with this
option.
* conditions - Specify the conditions that the associated objects must meet in order
to be included as a "WHERE" sql fragment, such as "price > 5 AND
name LIKE 'B%'".
* order - Specify the order in which the associated objects are returned as a
"ORDER BY" sql fragment, such as "last_name, first_name DESC"
* foreignKey - Specify the foreign key used for the association.
* By default this is guessed to be the name of this class in
lower-case and "_id" suffixed. So a Person class that makes a
has_many association will use "person_id" as the default
foreign_key.
* dependent - If set to true all the associated object are destroyed alongside
this object. May not be set if exclusive is also set.
* exclusive - If set to true all the associated object are deleted in one SQL
statement without having their beforeBestroy callback run. This
should only be used on associations that depend solely on this
class and don not need to do any clean-up in beforeDestroy. The
upside is that it's much faster, especially if there's a
counterCache involved. May not be set if dependent is also set.
* finderSql - Specify a complete SQL statement to fetch the association.
* This is a good way to go for complex associations that depends
on multiple tables. Note: When this option is used,
findInCollection is not used.
* counterSql - Specify a complete SQL statement to fetch the size of the association.
* If finderSql is specified but counterSql, counterSql will be
generated by replacing SELECT * FROM with SELECT COUNT(*) FROM.
*
*
* Setting $hasMany to a sting limits you alot.
* To use $hasMany as a string like this:
* [code]
* var $hasMany = 'association';
* [/code]
*
* You can also set more than one association in the string by seperating them with a comma
* [code]
* var $hasMany = 'association,association2,association3';
* [/code]
*/
var $hasMany = array('association1' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'order by',
'foreignKey' => 'foreign key',
'dependent' => true,
'exclusive' => false,
'finderSql' => 'custom SQL',
'counterSql' => 'custom SQL'),
'association2' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'order by',
'foreignKey' => 'foreign key',
'dependent' => false,
'exclusive' => true,
'finderSql' => 'custom SQL',
'counterSql' => 'custom SQL'),
'association3' =>
array('className' => 'class',
'conditions' => 'these conditions',
'order' => 'order by',
'foreignKey' => 'foreign key',
'dependent' => true,
'exclusive' => false,
'finderSql' => 'custom SQL',
'counterSql' => 'custom SQL'));
/**
* @var mixed $hasAndBelongsToMany this can be a string or an array.
*
* Example below is using an array and setting more than one hasAndBelongsToMany.
*
* Using hasAndBelongsToMany as an array gives you more control over the association
*
* association - Table holding the association
* className - Specify the class name of the association.
* Use it only if that name can not be inferred from the association
name.
* So
* [code]
* var $hasAndBelongsToMany = array(array('projects'));
* [/code]
* will by default be linked to the Project class, but if the real
class name is SuperProject, you will have to specify it with
this option.
* joinTable - Specify the name of the join table if the default based on lexical
order is not what you want. WARNING: If you're overwriting the table
name of either class, the tableName method MUST be declared
underneath any hasAndBelongsToMany declaration in order to work.
* foreignKey - Specify the foreign key used for the association.
* By default this is guessed to be the name of this class in
lower-case and "_id" suffixed. So a Person class that makes a
has_and_belongs_to_many association will use "person_id" as the
default foreign_key.
* associationForeignKey - Specify the association foreign key used for the
association. By default this is guessed to be the name of the
associated class in lower-case and "_id" suffixed. So the associated
class is Project that makes a hasAndBelongsToMany association will
use "project_id" as the default association foreignKey.
* conditions - Specify the conditions that the associated object must meet in order
to be included as a "WHERE" SQL fragment, such as "authorized = 1".
* order - Specify the order in which the associated objects are returned as an "ORDER
BY" SQL fragment, such as "last_name, first_name DESC"
* uniq - If set to true, duplicate associated objects will be ignored by accessors
and query methods
* finderSql - Overwrite the default generated SQL used to fetch the association
with a custom one
* deleteSql - Overwrite the default generated SQL used to remove links between the
associated classes with a custom one
* insertSql - Overwrite the default generated SQL used to add links between the
associated classes with a custom one
*
*
* Setting $hasAndBelongsToMany to a string limits you a lot.
* To use $hasAndBelongsToMany as a string like this:
* [code]
* var $hasAndBelongsToMany = 'Association';
* [/code]
*
* You can also set more than one association, by separating them with a comma:
* [code]
* var $hasAndBelongsToMany = 'Association,Association2,Association3';
* [/code]
*/
var $hasAndBelongsToMany = array('Association1' =>
array('className' => 'ClassNameInCamelCase',
'joinTable' => 'table to join on',
'foreignKey' => 'foreign key',
'associationForeignKey' => 'foreign key',
'conditions' => 'these conditions',
'order' => 'ORDER BY',
'uniq' => true,
第七章 Controllers
1.Controller 方法
1.1 和你的Views交互
1.2 使用Redirection
1.3 Controller的回调函数
1.4 其他有用的方法
2. Controller的变量
一个Controller是用来管理你应用某个方面的逻辑。大多数来说,controllers用来管理一个model的逻辑。比如,你正在建设一个站点来管理一个video的collection,你可能有一个VideoController以及一个RentalControlle来管理你的视频和租金。分别的,cake中每个controller的名字通常是复数。
程序的Controllers都是从AppController类继承来的类,AppController又是从核心的类Controller继承来的。Controller类可以包含任意数量的action:各种显示Views的方法
AppController类可以在/app/app_controller.php中第一,它里面包含了许多可以被更多controllers共享的方法,它本身是从核心类Controller继承来的。
一个Action是controller中的一个单独的方法,这个方法可以被Dispatcher自动的运行,运行的根据是从routes配置解析的页面请求。回到我们的 video collection的例子,VideoController类可以包含actions比如view(), rent(), search()等等,这个controller可以在/app/controllers/video_controller.php找到,并且文件内容为:
class VideosController extends AppController
{
function view($id)
{
//action logic goes here..
}
function rent($customer_id, $video_id)
{
//action logic goes here..
}
function search($query)
{
//action logic goes here..
}
}
你可以通过使用下面的URLs来调用这些方法:
http://www.example.com/videos/view/253
http://www.example.com/videos/rent/5124/0-235253
http://www.example.com/videos/search/hudsucker+proxy
但是这些页面将如何显示?你需要为每个action定义一个view,你可以在下一章查看具体内容。但是本章中,你会掌握Cake的controller,并且能够更好的使用。具体的说,你将学到如何用controller将你的数据传递给view,使用户转向以及其他更多功能。
1. Controller Functions
重要:
尽管本章中介绍了许多Cake中常用的方法,更多的手册内容请参考http://api.cake.org
1.1 和views交互
●set($var,$value)
○这个方法是将controller中的数据传递给view的主要方法。你可以使用这个方法控制任何值:single values, 整个数组等等。一旦你使用了set(),view中也可以使用这个变量:在controller中使用set(‘color’,’blue’)可以使得$color变量在view中使用
●validate()
○通过收集错误的保存,返回错误的个数
●validateErrors()
○根据model中第一的正确性规则,检查一个model的数据是否正确,更多信息参考第十章
●render($action=null, $layout=null, $file=null)
○你并非时刻需要这个方法,因为在每个controller方法的最后,render都被自动调用,并且调用后定义(或者使用)相应的view
1.2 使用转向
●redirect($url)
○使用这个方法告诉用户将跳转到哪里。这里的URL可以使Cake规则的URL或者使一个完整定义的URL(http://...)
●flash($message, $url, $pause=1)
○这个方法在你的flash layout(app/views/layouts/flash.thtml)中显示$message信息$pause秒钟,之后跳转到指定的URL
1.3 Controller的回调函数
Cake Controller定义了一系列回调函数,你可以使用他们在重要的controller function之前或者之后插入功能逻辑。实现这些功能,适用下面介绍的参数和返回值声明这些方法
●beforeFilter()
○在每个controller action之前调用,非常有用的地方去检查sessions是否有效,并检查相应的权限
●afterFilter()
○在每个controlleraction之后调用
●beforeRender()
○在controller逻辑之后,view显示之前调用
1.4 其他有用的方法
尽管这些方法是在Cake的Object类中,他们在Controller中也可以使用
●requestAction($url, $extra=array())
○这个方法根据任何地方(location)调用controller的action,然后返回已经显示的view.$url是Cake规范的URL(/controllername/actionname/params),如果$extra数组包含了一个键‘render’,controller action将自动设置AutoRender
●log($msg, $type = LOG_ERROR)
○你可以使用这个方法在你的程序应中记录发生的任何事件。记录文件Logs放在/tmp文件目录下
2. Controller的变量
数量使用controller中定义的变量可以使你更好的使用cake的某些附加功能
●$name
○PHP4 并不能以驼峰表示法将当前类的名称提供给我们。如果你遇到问题,使用这个变量将你的类名设置成正确的驼峰表示法
●$uses
○你的controller是否使用了很多的model?比如你的Fragglescontroller会自动调用$this->fraggle,但是你也想同时能够调用$this->smurf,那就将下面的语句加入到你的controller中
var $uses = array('Fraggle','Smurf');
●$helpers
○使用这个变量使得你的controller装在helpers到它的views. 这个HTML helper会自动装载,但是你可以使用这个变量来指定其他的
var $helpers = array('html','ajax','javascript');
●$layout
○将这个变量设置成为你在这个controller中想使用的layout
●$autoRender
○将这个变量设置成为false将会使得actions停止自动显示(rendering)
●beforeFilter
○如果你需要在某一个或者任何一个action调用之前都要运行一小段代码,使用$beforefilter.这个函数处理access control十分有用,你可以在任何action处理之前检查用户的权限。你需要做的就是将这个变量设置成为一个数组,数组中包含了你想运行的controller的action,如下所示
class ProductsController extends AppController
{
var $beforeFilter = array('checkAccess');
function checkAccess()
{
//Logic to check user identity and access would go here.
}
function index()
{
//When this action is called, checkAccess() is called first.
}
}
●$components
○和$helpers和$uses类似,这个变量用来装载你需要的components
var $components = array('acl');
第八章 Views
1.Views
一个View就是一个页面的模版,经常以action的名字来命名。举例来说,Postscontroller::add()方法的view存放在/app/views/posts/add.thtml。Cake的views文件都是简单的PHP文件,所以你可以在里面使用任何PHP代码,几乎所有的view文件都包含HTML,一个view可以使特定数据集的任何体现,包括XML,图片等等
在view的模版文件中,你可以从对应的Model中使用数据,这个数据以数组$data的形式传递过来,你在controller中使用set()传递过来的任何数据在view中都可以使用
注意
HTML helper默认情况下在任何一个view都是可用的。而且是views中使用最多的。它创建forms包括scripts和media、链接以及数据正确性检查中都非常有用。参考第九章第1.1节可以了解HTML helper更多的内容
views中许多可用的发放都是Helpers提供的。Cake提供了很多的helpers(参考第九章),你也可以引用自己定义的。因为views不应该包含过多的逻辑,所以views类中并没有很多public的方法。其中一个有用的方法就是renderElement(),这个方法我们在1.2节中讨论
1.1 Layouts
一个布局(layout)包括了围绕view的所有代码。你想在view中见到的所有东西都应该被放在你的layout中。 布局文件位于/app/views/layouts。
Cake的默认layout可以在/app/views/layouts/default.thtml被新的默认layout重写。一旦一个新的默认layout创建,controller view的代码将在页面被显示的时候替换到默认的layout
当你常见一个layout的时候,你需要告诉Cake你的controller view的代码位置:为了
达到这个目的,一定要确保layout包含$content_for_layout(有$title_for_layout更好)下面是一 个默认的layout的例子
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $title_for_layout?></title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<body>
<!-- IF you'd like some sort of menu to show up on all of your views, include it here -->
<div id="header">
<div id="menu"></div>
</div>
<!-- Here's where I want my views to be displayed -->
<?php echo $content_for_layout ?>
<!-- Add a footer to each displayed page -->
<div id="footer"></div>
</body>
</html>
你可以为你的cake站点创建任意多的layout,你所要做的就是把他们放到app/views/layouts这个目录下,并在使用controller actions的时候使用controllers的$layout
变量或者是setLayout()方法
举例来说,如果站点的一部分需要包含一个小的广告banner空间。可以创建一个新的带有小的广告空间的layout,并将这个layout设置成为controller actions将要使用的layout.方法如下:
var $layout = 'default_small_ad';
1.2 Elements
很多应用都有一些很多页面都会重复的代码段,有时候在layout中的位置不相同。Cake可以帮助你重现这些需要复用的部分。这些复用的部分叫做元素(Elements)。广告,帮助框,导航控制条,额外的菜单,插图编号在cake中就被实现为元素。一个元素就是其他views可以引用的小型view(a mini-view)
元素位于 /app/views/elements文件夹,并且都有.thtml的文件扩展名
例8.1 Calling an Element without parameters
<?php echo $this->renderElement('helpbox'); ?>
例 8.2 Calling an Element passing a data array
<?php echo
$this->renderElement('helpbox', array("helptext" => "Oh, this text is very helpful."));
?>
在一个元素文件中,所有传递的变量名称都是以通过传递过来数组的keys名获得(和controller中的set()在views中起到的作用很类似)。上面举的这个例子中 /app/views/elements/helpbox.thtml文件就会使用$helptext变量。当然,传递一个数组到元素文件会更有用的多。
使用元素可以使得view更易读,同时可以在一个文件中重复使用元素。他们也可以帮助你在网站建设中复用部分内容。