CakePHP自学笔记(六):模型的构建和关联
AquarTutorial 第一期
-CakePHP自学笔记
(一):利用Ubuntu搭建开发环境
(二):数据库配置与连接
(三):MVC开发模式简介
(四):CakePHP的命名规范
(五):Cake中的MVC开发
>>(六):模型的构建和关联
<-<-<-<-<-<-<-<-<-<-<-<-<-
“重构”的代价
直到想起来有这玩意才发现自己有多笨。。。所以郁闷了好几天没看,alpha版本里面也没有用到模型的关联,今天实在无聊的要命,就读了一下,然后改了DarkBook的代码,重新组织了数据的结构,麻烦不说,我还是搞不明白为什么都声明了’foreignKey’ => ‘owner’了,Cake还是返回没有User模型没有id的错误。God Damn It!!看来Cake习惯了每个模型都有个id当主键。>_<||。。。
所以刚才从数据库改起,模型、控制器、视图全有改动,幸亏DarkBook只有两个控制器,要不我肯定疯掉了——这就是不读完教程就乱写的后果。。。
四种关联
CakePHP提供了四种类型的关联:hasOne、hasMany、belongsTo和hasAndBelongsToMany。四者分别对应模型中一个同名的变量。
声明了模型之间的关联之后,我们(在一般情况下)就不需要在控制器中引入$uses变量来接收其他模型的数据了。比如在模型中我们可以用 $this->SomeOtherModel->someFunction() 来控制其他模型,或者在控制器中用 $this->SomeModel->SomeOtherModel->someFunction() 来控制其他模型。
hasOne
hasOne即“有一个”,比如一个User应该有一个Profile。那么我们就简单地这样声明:
<?php class User extends AppModel { var $name = 'User'; var $hasOne = 'Profile'; } ?>
注意,Cake需要外键(foreign key)来实现关联(跟我的方法差不多么。。。),hasOne需要在对应的模型(本例中的Profile)中包含外键,Cake默认的外键名称是原模型小写外加“_id”,本例中就是user_id。当然了,我们可以更改这个外键的值 ,hasOne还有其他的一些参数可以修改,列举如下:
- className 即关联到当前模型的模型类名。本例中就是Profile。
- foreignKey 在被关联模型中外键的名称,默认值就是当前模型类名小写后加“_id”。
- conditions 一条SQL语句用以过滤返回的关联模型。最好在语句中加上类名,比如”Profile.approved = 1″总是比”approved = 1″好的多。
- fields 获取关联模型数据时返回的字段列表。默认情况下返回全部。
- order 一条SQL语句用以定义返回的关联数据的排序。
- dependent 当这个值设置为true的时候,一旦对当前模型的某个记录调用了delete()函数并且参数cascade也设置成true,那么关联的模型记录也会被删除。本例中就是删除一个User也会删除关联给他的Profile。
可以用如下形式来设置这些参数的值(其他关联都类似):
<?php class User extends AppModel { var $name = 'User'; var $hasOne = array( 'Profile' => array( 'className' => 'Profile', 'conditions' => array('Profile.published' => '1'), 'dependent' => true ) ); } ?>
在控制器中用类似 $this->set(‘data’, $this->User->find(‘all’)) 之类的函数传递数据给视图后,我们在视图中就可以十分方便的调用各个模型了。
返回的结果类似这样:
//Sample results from a $this->User->find() call. Array ( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ) )
那么我们在视图中要用User的name字段的值,就可以 $data['User']['name'],要引用Profile的skill字段的值,就可以 $data['Profile']['skill']。
belongsTo
用hasOne我们已经可以从User的模型和控制器中获取Profile的数据了,相反地,我们可以设置belongsTo从Profile中获取所属User的数据。如下声明:
<?php class Profile extends AppModel { var $name = 'Profile'; var $belongsTo = 'User'; } ?>
与hasOne不同的是,belongsTo要求在当前模型中有外键。这个外键默认是belongsTo关联的模型的类名小写再加“_id”的后缀。这个关联与hasOne有很多相同的参数,包括className、foreignKey、conditions、fields和order,此外还有一下两个参数:
- counterCache 把这个参数设为true会导致关联模型的一个计数字段自动更改。这个计数字段的默认名是当前模型的类名小写加上“_count”后缀,在调用save()或者delete()时这个计数值就会变化。如果在这里添一个字符串,那么就把它作为计数字段的名称。
- counterScope 可选的条件用于确认计数字段的更新。
同hasOne类似,控制器传递给视图的数组类似下面:
//Sample results from a $this->Profile->find() call. Array ( [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ) [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) )
hasMany
下面来定义一个User有很多Comment的关联,用hasMany就可以做到在获取User数据的同时得到这个用户所写的评论。同hasOne类似的是外键要放在相关联的模型中。声明hasMany的方法不再赘述。
hasMany在hasOne的基础上还多了如下这些参数:
- limit 用这个设置返回的记录的最大数量。
- offset 获取关联数据前(在给定的conditions和order下)跳过的记录数量。
- exclusive 当这个值设置为true的时候,模型的递归删除会调用deleteAll()函数而不是一个一个删除。这样能极大提升效率,但并不一定适合所有情况。
- finderQuery 一条完整的SQL语句,CakePHP用来获取关联的数据。只在需要自己定义完全不同的功能时才需要。
控制器传递的数组像这样:
//Sample results from a $this->User->find() call. Array ( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) [Comment] => Array ( [0] => Array ( [id] => 123 [user_id] => 121 [title] => On Gwoo the Kungwoo [body] => The Kungwooness is not so Gwooish [created] => 2006-05-01 10:31:01 ) [1] => Array ( [id] => 124 [user_id] => 121 [title] => More on Gwoo [body] => But what of the ‘Nut? [created] => 2006-05-01 10:41:01 ) ) )
所以引用Comment时要注意用 $data['Comment'][1]等等,也可以 foreach $data['Comment'] as $single_comment 之类的。
hasAndBelongsToMany
最后这个有点不同,比如一个Post就“有并且属于很多”Tag,而HABTM和hasMany(用上面那个做例子)的区别就在于每个Comment被一个User拥有了之后,就不能再被别的User拥有了,而一个Tag属于一个Post之后还可以给其他的Post添加。
HABTM也不仅仅需要在当前模型或关联模型中的外键,它需要一个单独的包括两个模型名字的数据表,这个例子中相应的表就应该是posts_tags,一般需要3个字段——id、post_id、tags_id(哎,在Cake里写程序就记得每个表都来个id当主键,再设置成自动增长省的闹心。。。),HABTM有很多参数:
- className 关联的模型类名。
- joinTable 可以用这个参数设置关联表的名字。
- with 这里添的是关联表对应的模型名称。默认情况下CakePHP会自动创建一个模型。本例中默认的就叫做PostsTag。这个关联表也可以像普通的模型一样使用。
- foreignKey 当前模型中的外键值。在定义多个HABTM关联时会用到。默认值是当前模型类名小写加“_id”后缀。
- associationForeignKey 关联模型中的外键值。在定义多个HABTM关联时会用到。默认值是关联模型的类名小写加“_id”后缀。
- unique 如果设置为true(默认值),Cake会在添加新关联时删除已有的关联。(暂时不能理解透彻)
- conditions fields order limit offset 和hasMany一样。
- finderQuery deleteQuery insertQuery 分别可以添一条完整的SQL语句在获取、删除和添加关联的模型记录时使用。同样只在需要自定义的时候使用。
还是看看怎么声明HABTM关联:
<?php class Post extends AppModel { var $name = 'Post'; var $hasAndBelongsToMany = array( 'Tag' => array( 'className' => 'Tag', 'joinTable' => 'recipes_tags', 'foreignKey' => 'recipe_id', 'associationForeignKey' => 'tag_id', 'unique' => true, 'conditions' => '', 'fields' => '', 'order' => '', 'limit' => '', 'offset' => '', 'finderQuery' => '', 'deleteQuery' => '', 'insertQuery' => '' ) ); } ?>
控制器传递给视图的数组同hasMany类似,不再赘述。




