分类:
2007-09-14 16:10:00
我们已经加入了一些model回调(函数),它们允许你在某个model操作前或后悄悄的加点逻辑在里面。为了在应用程序中使用本功能,使用提供的参数,并且在Cake Model里覆盖这些函数。
beforeFind
beforeFind()回调函数仅在一个查找操作之前执行。可以在本方法里放入任何预先查找的逻辑。当你在model里覆盖时,如果你想执行查找,返回true,若是想取消,返回false。
afterFind
使用本回调会修改一个查询操作返回的结果,或者进行其他的post查找逻辑。Model查找操作返回的结果就是本函数的参数,并且返回值就是修改的结果。
beforeValidate
在model验证前使用此回调修改model数据。它也能用来增加额外的,更加复杂的验证规则,使用Model::invalidate()验证。在本上下文中,model数据可以通过$this->data访问。本函数也必须返回true,否则save()执行会终止。
beforeSave
在本函数中加入任何预保存的逻辑。本函数在model 数据验证后(假设它一验证,否则save()调用取消,并且本回调不会执行)立即执行。但是在数据保存之前,如果你想保存工作本函数也会返回true,本函数也应该返回true,如果你想让保存操作继续,如果取消,则返回false。
beforeSave的一个用法可以是格化式指定数据库引擎上的时间数据。
/ Date/time fields created by HTML Helper: // This code would be seen in a view $html->dayOptionTag('Event/start'); $html->monthOptionTag('Event/start'); $html->yearOptionTag('Event/start'); $html->hourOptionTag('Event/start'); $html->minuteOptionTag('Event/start'); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ // Model callback functions used to stitch date // data together for storage // This code would be seen in the Event model: function beforeSave() { $this->data['Event']['start'] = $this->_getDate('Event', 'start'); return true; } function _getDate($model, $field) { return date('Y-m-d H:i:s', mktime( intval($this->data[$model][$field . '_hour']), intval($this->data[$model][$field . '_min']), null, intval($this->data[$model][$field . '_month']), intval($this->data[$model][$field . '_day']), intval($this->data[$model][$field . '_year']))); } |
在本回调方法中,每次保存之后放入你想执行的任何逻辑。
在本函数中放置任何预删除逻辑。如果你想让删除操作继续的话,本函数应该返回true。否则你想终止的话则返回false。
在本回调方法里,每个删除操作之后,放置你想执行的任何逻辑。
当创建model时,你需要设置某些特定的变量来访问Cake的功能:
$primaryKey
如果model和一个数据库表相对应,并且表的主键的命名不是”id”,那么使用本变量告诉Cake你的主键名。
$recursive
它将设置Cake使用find()和findAll()操作获取相关联model数据的层数。
假想你有一个组(Group),每组有许多用户(User),而这些用户又有很多文章(Article)。
Model::recursive 选项
$recursive = 0 |
Cake 获取Group |
$recursive = 1 |
Cake 获取Group以及相关联的Users |
$recursive = 2 |
Cake 获取Group, 相关联的Users, 以及Users关联的Articles |
$transactional
告诉Cake是否为本model启用事务(例如,begin/commit/rollback)。设置为一个布尔值。仅当数据库支持时。[1]
$useTable
如果你想使用的数据库表不是复数格式的model名(以及你不打算修改表名),将本变量设置为你想让model使用的表名。
$validate
用来验证传递到model的数据。参看第12章。
$useDbConfig
记住了在/app/config/database.php配置的数据库设置了吗?使用本变量来切换他们-使用在数据库配置文件里创建的数据库链接变量的名称。你已经猜到,缺省的是‘defualt’。
CakePHP最厉害的特性之一就是Model提供的关系映射。在CakePHP中,表之间的关系是通过关联处理的。关联就是相关逻辑单元之间的胶水。
在CakePHP有4中关联:
1. hasOne
2. hasMany
3. belongsTo
4. hasAndBelongsToMany
当定义model之间的关系时,Cake会自动获取与正在工作的model相关的model。例如,如果一个Post Model与Author Model相关,并使用hasMany关联,调用Controller的$this->Post->findAll()将会获得Post记录,同时也会获得与他们相关的Author记录。
为正确使用关联,建议遵循CakePHP命名规则(参考附录)。如果你使用了CakePHP的命名规则,你也可以使用scaffolding可视化你的应用数据,因为scaffolding检测并使用model之间的关联。当然,在没遵循Cake的命名规则时,你也可以一直自定义model关联来进行工作,但我们会在后面说明一些技巧。现在,让我们盯住这些规则吧。在这里我们关心的命名规则是主键,Model名,以及表名。
下面是Cake期望这些不同元素名称的概览:(参看附录获取更多关于命名的信息):
1. 外键:【单数model名】_id.例如,可以将指回到Author属于的Post的“author”表的外键命名为”post_id”.
2. 表名:【复数的对象名】,因为我们想存储Blog post和作者的信息,表名应该分别为"posts" 和"authors"
3. Model名:【骆驼峰命名,表名的单数形式】。"posts" 表的Model名为"Post","authors"表的model名为"Author"
CakePHP的Scaffolding希望你的关联与你的列保持同样的顺序。因此如果你有一个Article belongsTo(属于)3个其他的model(Author, Editor, 和Publisher),你需要3个键:uthor_id, editor_id, Publisher_id.Scaffolding期望你的关联和表中的键保持一样的顺序(例如,第一个是Author,第二个是Editor,最后是Publisher)。
为了描述这些关联如何工作,让我们继续使用Blog应用程序作为实例吧。假设我们打算为blog创建一个简单的用户管理系统。也假设它会在不跟踪Users的情况下进行,但是我们希望每个用户都有一个关联的Profile(User hasOne Profile).Users也会创建留言并且保留他们的关联(User hasMany Comments),一旦我们让用户系统运行,我们会将视线转移到使用hasAndBelongsToMany(Post hasAndBelongsToMany Tags)Posts以及与其相关的Tag对象。
为建立关联,我们假设你已经创建了User以及Profile Model。为了定义他们的hasOne关联,我们需要为Model增加一个数组告诉Cake它们是怎样关联的。这里是它们如何关联的:
/app/models/user.php hasOne
class User extends AppModel { var $name = 'User'; var $hasOne = array('Profile' => array('className' => 'Profile', 'conditions' => '', 'order' => '', 'dependent' => true, 'foreignKey' => 'user_id' ) ); } ?> |
$hasOne数组是Cake用来创建User和Profile model之间的关联的。数组中的每个键允许你更进一步的配置关联:
1. className (必须): 关联的model 类名。
例如,我们会指定'Profile' model类名。
2. conditions: SQL条件部分,它定义了关系。
我们可能会使用它来告诉Cake只关联Profile,此Profile有一个绿色的标记头,如果我们愿意。为了定义这个条件,可以为此键指定一个SQL条件作为其值:”Profile.header_color = 'green'"。
3. order:关联model的顺序
例如,如果你想让你的关联model以某顺序排列,为此键设置一个SQL排序谓语:"Profile.name ASC"。
4. dependent:如果设置为true,当它销毁时,相关联的model也会销毁。
例如,如果"Cool Blue"的Profile和"Bob"相关联,并且我们删除用户"Bob","Cool Blue"的Profile也会删除。
5. foreignKey:指向关联的model的外键名。
在这里,你正在操作一个没有遵循Cake命名规则的数据库。
现在,当使用Profile model来执行 find()或findAll()时,我们应该也看到相关联的User model:
$user = $this->User->read(null, '25'); print_r($user); //输出: Array ( [User] => Array ( [id] => 25 [first_name] => John [last_name] => [username] => psychic [password] => c4k3roxx ) [Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 ) ) |
如果User想看到他的Profile,我们需要定义一个关联,因此Profile可以看见他自己的User。在Cake里,可以使用belongsTo关联实现。在Profile model里,我们可以如下操作:
/app/models/profile.php belongsTo
class Profile extends AppModel { var $name = 'Profile'; var $belongsTo = array('User' => array('className' => 'User', 'conditions' => '', 'order' => '', 'foreignKey' => 'user_id' ) ); } ?> |
$belongsTo数组是Cake用来创建User和Profile model之间的关联的。数组中的每个键允许你更进一步的配置关联:
1. className (必须):你想要关联的model的类名
例如:我们想指定‘User’model 类名。
2. conditions:定义关系的SQL条件语句
我们可以使用它告诉Cake仅关联活动的User。为了实现它,将键值设置为"User.active = '1'"或者其他类似的。
3. order:关联model的顺序。
如果你想让你的关联model以某顺序排列,为此键设置一个SQL排序谓语:"User.last_name ASC"。
6. foreignKey: 指向关联model的外键名。
在这里,你正在操作一个没有遵循Cake命名规则的数据库。
现在,当使用Profile model执行 find()或findAll(),我们应该也可以看到相关联的User model:
$profile = $this->Profile->read(null, '4'); print_r($profile); //output: Array ( [Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 ) [User] => Array ( [id] => 25 [first_name] => John [last_name] => [username] => psychic [password] => c4k3roxx ) ) |
尽管User和Profile model已经关联,并且工作正常,让我们再构建我们的系统,以至User记录和Comment记录关联。在User model中可以如下定义:
/app/models/user.php hasMany
class User extends AppModel { var $name = 'User'; var $hasMany = array('Comment' => array('className' => 'Comment', 'conditions' => 'Comment.moderated = 1', 'order' => 'Comment.created DESC', 'limit' => '5', 'foreignKey' => 'user_id', 'dependent' => true, 'exclusive' => false, 'finderQuery' => '' ) ); // Here's the hasOne relationship we defined earlier... var $hasOne = array('Profile' => array('className' => 'Profile', 'conditions' => '', 'order' => '', 'dependent' => true, 'foreignKey' => 'user_id' ) ); } ?> |
$hasMany数组是Cake用来创建User和Comment model之间的关联的。数组中的每个键允许你更进一步的配置关联:
1. className(必须):你想要关联的model的类名
例如:我们想指定‘Comment’model 类名。
2. conditions: 定义关系的SQL条件语句
我们可以使用它告诉Cake仅关联通过管理的Comment。为了实现它,将键值设置为" Comment.moderated = 1"或者其他类似的。
3. order: 关联model的顺序。
如果你想让你的关联model以某顺序排列,为此键设置一个SQL排序谓语:"Comment.created DESC "。
4. limit:你想让Cake获取关联model的最大数
在本例,我们不会获取所有用户的留言,仅仅为5.
5. foreignKey: 指向关联model的外键名。
在这里,你正在操作一个没有遵循Cake命名规则的数据库。
6. dependent:如果设置为true,当它销毁时,相关联的model也会销毁。
例如,如果"Cool Blue"的Profile和"Bob"相关联,并且我们删除用户"Bob","Cool Blue"的Profile也会删除。
7. exclusive:如果设置为true,所有关联的对象在没有让beforeDelete回调运行时在一个SQL语句中会被删掉,
对于比较简单的关联,使用起来很好,因为它能更快。
8. finderQuery:指定一个完整的SQL语句获取关联。
对于复杂的依赖多个表的关联,这是一种优秀的方法。如果Cake的自动关联不工作,在这里,你可以定义它。
现在,当使用User model执行 find()或findAll(),我们应该也可以看到相关联的Comment model:
$user = $this->User->read(null, '25'); print_r($user); //输出: Array ( [User] => Array ( [id] => 25 [first_name] => John [last_name] => [username] => psychic [password] => c4k3roxx ) [Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 ) [Comment] => Array ( [0] => Array ( [id] => 247 [user_id] => 25 [body] => The hasMany assocation is nice to have. ) [1] => Array ( [id] => 256 [user_id] => 25 [body] => The hasMany assocation is really nice to have. ) [2] => Array ( [id] => 269 [user_id] => 25 [body] => The hasMany assocation is really, really nice to have. ) [3] => Array ( [id] => 285 [user_id] => 25 [body] => The hasMany assocation is extremely nice to have. ) [4] => Array ( [id] => 286 [user_id] => 25 [body] => The hasMany assocation is super nice to have. ) ) ) |
在这里,当我们不打算记录处理过程时,定义"Comment belongsTo User"关联也是一个相当不错的注意,因此2个model都能看到对方。当你试图使用scaffolding时,未定义2个model之间的关联常常是一个常见的难题。