Aug
21
默认情况下,Cake使用'AND'来连接多个条件;这意味着,上面的示例代码检索结果为过去2周内title为"First post", "Second post"或者"Third post"的记录。当然我们也同样可以使用其他的逻辑运算符来连接查询条件:
<?
array
("or" =>
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
)
?>
Cake可以使用任何SQL语句中允许的逻辑运算符,如AND, OR, NOT, XOR等等,并且大小写不敏感(Conditions可以无限嵌套,但我并不推荐使用这样的magic code)。Posts和Authors两个对象间分别是hasMany/belongsTo的关系(熟悉Hibernate的同学或许更喜欢一对多多对一的叫法)。假设你希望检索所有过去两周内发布的posts或者是包含有指定关键字的posts,并且你希望限定作者为Bob,让我们看如下代码:
<?
array
("Author.name" => "Bob", "or" => array
(
"Post.title" => "LIKE %magic%",
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")
)
)
?>
保存数据
当需要保存model对象时(译注:或者使用持久化这个词更贴切),你需要提供如下形式的数据给save()方法:
<?
Array
(
[ModelName] => Array
(
[fieldname1] => 'value'
[fieldname2] => 'value'
)
)
?>
为了能够让数据通过这样的形式提交给controller,最方便的办法就是使用HTML Helper来完成这个任务,因为HTML Helper会为提交的Form封装成Cake希望的这种形式。当然你可以不使用,只要页面上的元素的name被设置成date[Modelname] [fieldname]形式就ok了。不过我还是要说,$html->input('Model/fieldname')是最方便的办法。
(译注:OGNL的php版,太棒了,我的意见是如果不嫌麻烦的话尽量使用类似OGNL的做法,因为tag产生的页面在设计期是无法预览的,我相信web应用前台页面的设计的复杂性并不亚于后台业务逻辑)
从页面Form中提交的数据自动被格式化并且注入到controller中的$this->data变量,所以保存从web页面提交的数据只是举手之劳。下面我们来看一段示例代码:
<?
function edit($id)
{
//Note: The property model is automatically loaded for us at $this->Property.
// Check to see if we have form data...
if (emptyempty($this->data))
{
$this->Property->id = $id;
$this->data = $this->Property->read();//populate the form fields with the current row
}
else
{
// Here's where we try to save our data. Automagic validation checking
if ($this->Property->save($this->data['Property']))
{
//Flash a message and redirect.
$this->flash('Your information has been saved.',
'/properties/view/'.$this->data['Property']['id'], 2);
}
//if some fields are invalid or save fails the form will render
}
}
?>
注意保存数据前会触发model的校验机制,更多关于数据校验的内容请参见Chapter 12。如果你不希望进行数据校验,可以使用save($date, false)。
其他一些有用的数据保存函数
del
string $id
boolean $cascade
删除指定id的model对象,或者当前model对象。
如果$cascade设为true,则会级联删除当前model所关联的所有model中,设为'dependent'的model对象。删除成功返回true
saveField
string $name
string $value
保存单个属性值。
getLastInsertId
返回最后当前ID属性的nextValue。
[ToDo 扩展支持多种主键生成策略 例如sequence UUID]
Model中的回调函数
我们在model中增加了一些回调函数以帮助你在model操作前后能够织入一些业务逻辑(原文为sneak in,借用了AOP中的织入一词,因为从操作来看这些回调函数等同于AOP中的advice)。为了获得这样的能力,需要使用model中的一些参数并且在你的model中覆写这些方法。
beforeFind
string $conditions
beforeFind()回调函数是在model的find方法执行前的前置操作。你可以加入任何检索前的业务逻辑。你覆写该方法只要保证在前置操作成功后返回true来执行真正的find方法,返回false中断find方法就可以了。(译注:在一些复杂场景中,需多次持久化的情况下请慎用)
afterFind
array $results
使用afterFind回调函数能够更改find方法的返回结果集,或者在检索动作完成后加上一些业务逻辑。该函数的参数$results为经过回调函数处理以后的find检索结果集。
beforeValidate
beforeValidate回调函数能够在model校验数据之前更改model中的一些数据。同样也可以用来在model校验之前加入更为复杂的额外校验规则。和beforeFind一样,必须保证返回true来调用真正的操作,返回false来中断校验乃至save操作。
beforeSave
和先前介绍的回调函数类似,在校验完成之后,保存动作之前加入额外的处理(如果校验失败是不会触发该回调函数的)。返回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'])));
}
afterSave
[code]
保存完成后执行的动作。[ToDo 如果保存出错是否会触发?]
[code]
beforeDelete
afterDelete
不需要多说了吧,删除操作前后的回调函数。