CakePHP中文手册【翻译】-Model (一)
时间:2007-09-14 来源:youngpand
Model
第1节
model是什么?
model是什么?是MVC中的M。
它能做什么?把逻辑从表现层中分离出来,独立应用程序的逻辑。
一般来说,model是一个数据库的访问入口,更特殊的是,它是某个特定数据库表会的访问入口。缺省的,每个model使用数据表,此表的表名是它自己的复数形式,例如,‘User‘model使用’users‘表。Model也可以包含数据验证规则,关联信息,以及指定到它使用的表的方法。下面是一个简单的User model在Cake中的样子:
User model实例,保存在app/models/user.php
//AppModel gives you all of Cake's Model functionality
class User extends AppModel
{
// Its always good practice to include this variable.
var $name = 'User';
// This is used for validation, see Chapter 11.
var $validate = array();
// You can also define associations.
// See section 6.3 for more information.
var $hasMany = array('Image' =>
array('className' => 'Image')
);
// You can also include your own functions:
function makeInactive($uid)
{
//Put your own logic here...
}
}
?>
第2节
Model 功能
从PHP的角度看,model扩展了AppModel类。AppModel类在cake/目录中定义,如果你想创建你自己的类,请把它放在app/app_model.php.它应该包含在2个或更多的model之间可共享的方法。它自己扩展了Model类,此类是一个标准的Cake库,定义在cake/libs/model.php中。
本节介绍大部分常用的Cake Model函数。记住使用
http://api.cakephp.org
获取全部参考,这是非常重要的。
用户定义函数
在Model中,某个特定表的函数的例子是一对用来隐藏/显示blog中的post的方法。
Model 函数实例
class Post extends AppModel
{
var $name = 'Post';
function hide ($id=null)
{
if ($id)
{
$this->id = $id;
$this->saveField('hidden', '1');
}
}
function unhide ($id=null)
{
if ($id)
{
$this->id = $id;
$this->saveField('hidden', '0');
}
}
}
?>
获取数据
下面是一些用来获取数据的标准model方法。
findAll
string $conditions
array $fields
string $order
int $limit
int $page
int $recursive
返回符合$conditions(如果有的话)并且上限为$limit条的指定字段,并从页面$page(缺省为页面1)开始列出。$conditions看起来和他们在SQL语句里的一样,例如$conditions = "race = 'wookie' AND thermal_detonators > 3"。
当$recursive设置为一个大于1的整数时,findAll()操作会尽可能返回与findAll()找到的那些相关联的model。如果你的财产(Property)有多个拥有者,并且他们拥有多个合同(contract),那么一个Property model的findAll()方法将递归返回这些相关的model。
find
string $conditions
array $fields
string $order
int $recursive
返回匹配$conditions的第一个记录的指定字段(或所有字段,如果没有指明)。
当$recursive选项设置为一个1到3之间的整数值,findAll()操作尽可能返回与findAll()找到的那些相关联的model。递归查找最深可到第3层。如果你的财产(Property)有多个拥有者,并且他们拥有多个合同(contract),那么一个Property model的递归find()方法将返回最多三层深的关联model。
findAllBy
string $value
这些魔幻函数可以作为一个快捷方式来查询你的表,并获得一行给定了特定的字段,特定的值的记录。将你想查询的字段名字放上去,并使用骆驼峰的格式。实例(在Controller里)可以为
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLastName('Rogers');
$this->Property->findAllByState('AZ');
$this->Specimen->findAllByKingdom('Animalia');
返回值是一个数组,并且按find()或findAll()那样的格式进行格式化.
findNeighbours
string $conditions
array $field
string $value
返回一个相邻的Model数组(仅用指定的字段),并由$field和$value指定,由SQL条件$conditions进行过滤。
在这种情形下,它是非常价值的。你可以让用户通过'Previous'和'Next'的链接在你的model入口里获取有序的记录。它仅对数字和日期字段有效。
class ImagesController extends AppController
{
function view($id)
{
// Say we want to show the image...
$this->set('image', $this->Image->find("id = $id");
// But we also want the previous and next images...
$this->set('neighbours', $this->Image->findNeighbours(null, 'id', $id);
}
}
它会给我们一个全集的$image['Image']数组,并在view中接着有 $neighbours['prev']['Image']['id'] 以及$neighbours['next']['Image']['id'] 。
field
string $name
string $conditions
string $order
返回一个字符串,即匹配$conditions 条件以及$order顺序的第一个记录的单个字段。
findCount
string $conditions
返回与给定条件匹配的记录数。
generateList
string $conditions
string $order
int $limit
string $keyPath
string $valuePath
本函数是可以快捷的得到一键/值列—特别是对手动创建一个model的HTML select标记。使用$conditions, $order, 以及$limit这些参数来作出一个findAll()请求。通过$keyPath和$valuePath,告诉model在哪里找到生成列表的键与值。例如,如果你打算生成一列基于Role Model的角色,并且键为它们的整数id,完整的调用可以如下:
$this->set(
'Roles',
$this->Role->generateList(null, 'role_name ASC', null, '{n}.Role.id', '{n}.Role.role_name')
);
//This would return something like:
array(
'1' => 'Account Manager',
'2' => 'Account Viewer',
'3' => 'System Manager',
'4' => 'Site Visitor'
);
read
string $fields
string $id
使用本函数得到当前已加载记录的字段以及它们的值,或者为$id的记录。
请注意,read()操作仅仅获得第一层相关model值,与model里$recursive值没有关系。为了获取其他层,使用find()或findAll().
query
string $query
execute
string $query
可以使用model的query()和execute()来执行自定义的SQL调用。两者之间的区别是query()用来执行自定义的SQL查询(返回结果),而execute()用来执行自定义的SQL命令(不需返回值)。
使用query()的自定义SQL调用
class Post extends AppModel
{
var $name = 'Post';
function posterFirstName()
{
$ret = $this->query("SELECT first_name FROM posters_table
WHERE poster_id = 1");
$firstName = $ret[0]['first_name'];
return $firstName;
}
}
?>
复杂的查找条件(使用Array)
大多数model的查找调用会以这样那样的方式传入一组条件。解决此最简单的方式就是在SQL里使用WHERE子句,但是如果需要更多的控制,你可以使用数组。数组的使用可以使读取更加清楚,同时也更加简单,而且使查询的创建变得相当简单。本语法也将查询的元素(字段,值,操作等)变成严谨但可控制的部分。这让Cake可以生成最有效的查询,并保证恰当的SQL语法,以及脱离每个查询的独立部分。
最基础的是,一个基于数组的查询可以这样:
使用Array的基本查询条件实例
$conditions = array("Post.title" => "This is a post");
//Example usage with a model:
$this->Post->find($conditions);
本结构自己就能非常好的解释它自己:它会查找任何title为"This is a post"的post。注意我们在前面可以把“title”作为字段名,但是在建立查询时,一直指定model名将会是一个优秀的实践,因为它改进了代码的清晰性,并帮助阻止未来的冲突,因为在未来你可能会选择改变你的schema。那么其他的匹配呢?同样简单。让我们查找一些title不是"This is a post"的post:
array("Post.title" => " This is a post")
就在表达式前增加一个'‘。Cake可以解析任何有效的SQL比较操作符,包括匹配表达式,如LIKE,BETWEEN,或REGEX,只要你在表达式或值等操作符之间留一个空格。这里还是有一个例外,那就是IN(…)样式的匹配。查找title为给定值的post可以是:
array("Post.title" => array("First post", "Second post", "Third post"))
在条件中,同样简单增加额外的条件和增加额外的键/值对到数组中:
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
缺省的,Cake将多个条件组成AND,意思就是,上面的片段仅仅匹配那些在2周前创建的post,而且title需要匹配其中一个给定的值。虽说如此,我们可以很容易的查找那些匹配任何条件的post:
array
("or" =>
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
)
Cake接受所有有效的SQL布尔操作,包括ND, OR, NOT, XOR等,并且它们可以为大写,也可以为小写,不管你喜欢哪种。这些条件也可无限嵌套。Posts和Authors之间的关系是hasMany/belongsTo,它会使POST上的查询有一个LEFT JOIN操作。你打算查找所有包含某个关键字或在2周前创建的Post,但是你想约定这些Post为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来实现,因为它创建表单元素,这些元素都以Cake期望的方式命名的。当然,你也没有必要使用它:保证你的表单元素按类似data[Modelname][fieldname]的方式命名。最简单的方式是使用$html->input('Model/fieldname')。
表单Post的数据会自动格式化,并将$this->data 放入Controller里。因此保存web表单的数据是非常简单的。一个合适的controller编辑函数可能看起来如下:
function edit($id)
{
//Note: The property model is automatically loaded for us at $this->Property.
// Check to see if we have form data...
if (empty($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
}
}
注意,save操作是怎样在一个条件语句中放置的:当你试图将数据保存到model时,Cake自动试图根据你提供的规则验证数据。为了学到更多关于数据验证的知识,参看
第12章
。如果你不想让save()验证数据,使用save($data, false).
其他有用的存储函数:
del
string $id
boolean $cascade
删除指定$id的model,或者model的当前id。如果这个model和其他model相关联,并且'dependent'间已经在关联数组中设置,本方法也会删除那些关联的model,如果$cascade设为true的话。
如果成功返回true。
saveField
string $name
string $value
用来保存单个字段值。
getLastInsertId
返回最近创建记录的ID。
相关阅读 更多 +
排行榜 更多 +