This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
khosb/includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md
2011-05-03 09:49:01 +10:00

10 KiB
Raw Blame History

ORM

Kohana 3.0 包含一个强劲的 ORM 扩展,作用于记录模式,数据库内省来确定模型的列表。

ORM 扩展默认包含在 Kohana 3.0 之中,但是如要使用它则需要先开启它。修改 application/bootstrap.php 文件中的 [Kohana::modules] 方法并加载 ORM 扩展:

Kohana::modules(array(
	...
	'orm' => MODPATH.'orm',
	...
));

配置

通过一些配置 ORM 才能工作。通过在模型类继承 ORM

class Model_User extends ORM
{
	...
}

上面的例子中,模型会寻找默认数据库的 users 表。

模型配置属性

下面的属性是用于配置每个模型的:

类型 属性 描述 默认值
string _table_name 表名 singular model name
string _db 数据库配置名 default
string _primary_key 主键 id
string _primary_val 主键值 name
bool _table_names_plural 表名是否是复数形式 TRUE
array _sorting 列名 => 排序方向的数组 primary key => ASC
string _foreign_key_suffix 外键的后缀 _id

使用 ORM

加载一条记录

通过调用 [ORM::factory] 或 [ORM::__construct] 方法创建模型的实例化:

$user = ORM::factory('user');
// 或者
$user = new Model_User();

构造函数和 factory 方法也接受一个主键值来加载模型数据:

// 加载 ID 为 5 的用户
$user = ORM::factory('user', 5);

// 检查用户是否加载成功
if ($user->loaded()) { ... }

你同样可以使用传递键-值型数组的数据对象去加载记录:

// 加载 email 为 oe@example.com 的用
$user = ORM::factory('user', array('email' => 'joe@example.com'));

搜索记录

ORM 支持大多数的 [Database] 方法来强劲驱动搜索模型中的数据。ORM 类的 _db_methods 属性列出了所有支持调用的方法列表。记录的搜索可以通过 [ORM::find] 和 [ORM::find_all] 方法调用获得。

// 搜索活跃用户中名为 Bob 的第一条记录
$user = ORM::factory('user')
	->where('active', '=', TRUE)
	->where('name', '=', 'Bob')
	->find();

// 搜索名为 Bob 的所有用户
$users = ORM::factory('user')
	...
	->find_all();

当你使用 [ORM::find_all] 搜索一批记录模型,你可以使用迭代从数据库结果中获取每条记录模型:

foreach ($users as $user)
{
	...
}

ORM 一个强大的特性是 [ORM::as_array] 方法,它把返回的记录集转为为一个数组。如果使用了 [ORM::find_all] 所有的记录都会以数组的形式返回。 对于选择列的时候是非常好用的:

// 显示选择列的用户名 (使用 id 作为其值)
form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username') ...

记录数

使用 [ORM::count_all] 方法返回查询返回记录集的记录数。

// 用户的记录数
$count = ORM::factory('user')->where('active', '=', TRUE)->count_all();

如果你想在特定子集的查询语句中统计所有用户的记录数,在调用 count_all 方法之前先调用 [ORM::reset] 方法并赋值 FALSE:

$user = ORM::factory('user');

// 用户的总数 (reset FALSE prevents the query object from being cleared)
$count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all();

// 仅返回前 10 条记录的记录数
$users = $user->limit(10)->find_all();

取出模型属性

所有的模型属性都可以通过 PHP 的魔法方法 __get__set 得到读写权。

$user = ORM::factory('user', 5);

// 输出用户名
echo $user->name;

// 更改用户名
$user->name = 'Bob';

假如保存的信息/属性并不存在于模型表中,使用 _ignored_columns 来忽略数据成员。

class Model_User extends ORM
{
	...
	protected $_ignored_columns = array('field1', 'field2', ...)
	...
}

使用 [ORM::values] 方法设置键-值型数组:

$user->values(array('username' => 'Joe', 'password' => 'bob'));

创建并存储记录

[ORM::save] 方法既可以用于创建新记录也可作用于更新现有记录。

// 创建新记录
$user = ORM::factory('user');
$user->name = 'New user';
$user->save();

// 更新现有记录
$user = ORM::factory('user', 5);
$user->name = 'User 2';
$user->save();

// 检查记录是否保存成功
if ($user->saved()) { ... }

你也可以使用 [ORM::save_all] 方法来更新多条记录:

$user = ORM::factory('user');
$user->name = 'Bob';

// 更新所有结果记录的名字为 'Bob'
$user->where('active', '=', TRUE)->save_all();

使用 UpdatedCreated

_updated_column_created_column 变量是用于当模型更新或插入新纪录的时候自动更新设置的字段值。默认没有使用。如果你想使用:

// date_created 列用于储存创建的时间,使用 TRUE 保存的是时间戳(timestamp)
protected $_created_column = array('date_created' => TRUE);

// date_modified 列用于储存最后修改时间。这里的时间设置为使用 date() 格式后的字符串
protected $_updated_column = array('date_modified' => 'm/d/Y');

删除记录

删除记录可以使用 [ORM::delete] 和 [ORM::delet_all] 方法。这两个方法的使用和上面 存储记录 方法类似,但有一点不同的是 [ORM::delete] 方法带有一个删除记录 'id' 的可选参数。

关系

ORM 提供强大的关系模型。Ruby 有一篇介绍关系模型的文章: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Belongs-To 和 Has-Many

假设我们在一所学校工作,当然学校有很多学生,而每个学生都只属于一个学校。这样的关系模型可以这样定义:

// school 模型文件
protected $_has_many = array('students' => array());

// student 模型文件
protected $_belongs_to = array('school' => array());

获取学生的学校:

$school = $student->school;

获取学校的学生:

// 注意在 studends 后必须调用 find_all 方法
$students = $school->students->find_all();

// 缩小范围查询:
$students = $school->students->where('active', '=', TRUE)->find_all();

默认情况下,在 student 表定义的模型文件中 ORM 会寻找 school_id 当作外键。这个可以通过 foreign_key 属性更改:

protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID'));

外键应该同时覆写 student 和 school 模型文件。

Has-One

Has-One 是 Has-Many 的一个特别情况,唯一不同的这是一对一关系。还以上面的例子说明就是,每个学校有且只有一个学生(当然这是一个很牵强呃例子)。

// school 模型文件
protected $_has_one = array('student' => array());

类似于 Belongs-To当你引用 Has-One 关系对象的时候无需调用 find 方法 - 它是自动完成的。

Has-Many "Through"

Has-Many "through" 关系(也可以称之为 Has-And-Belongs-To-Many) is used in the case of one object being related to multiple objects of another type, and visa-versa. For instance, a student may have multiple classes and a class may have multiple students. In this case, a third table and model known as a pivot is used. In this case, we will call the pivot object/model enrollment.

// student (学生)模型文件
protected $_has_many = array('classes' => array('through' => 'enrollment'));

// class (班级)模型文件
protected $_has_many = array('students' => array('through' => 'enrollment'));

其中 enrollment 表包含两个外键: class_idstudent_id。在定义关系时,使用 foreign_keyfar_key 覆写了默认值。例如:

// student (学生)模型文件() (the foreign key refers to this model [student], while the far key refers to the other model [class])
protected $_has_many = array('classes' => array('through' => 'enrollment', 'foreign_key' => 'studentID', 'far_key' => 'classID'));

// class (班级)模型文件
protected $_has_many = array('students' => array('through' => 'enrollment', 'foreign_key' => 'classID', 'far_key' => 'studentID'));

enrollment 模型文件应该这样定义:

// Enrollment 模型同时属于一个 student 和 class
protected $_belongs_to = array('student' => array(), 'class' => array());

获取相关对象:

// 从 student 中获取 classes
$student->classes->find_all();

// 从 class 中获取 students
$class->students->find_all();

校验

ORM 和 [Validate] 类是紧密结合使用的。ORM 提供以下几种校验方式:

  • _rules
  • _callbacks
  • _filters
  • _labels

_rules

protected $_rules = array
(
	'username' => array('not_empty' => array()),
	'email'    => array('not_empty' => array(), 'email' => array()),
);

检测并确保 username 字段不为空。检测 email 字段不为空且是有效的 Email 地址格式。那些传递空值数组用于提供可选的额外参数到校验方法中使用。

_callbacks

protected $_callbacks = array
(
	'username' => array('username_unique'),
);

username 字段被传递到了 username_unique 回调函数。如果方法存在于当前模型它就会被调用,否则调用全局函数。下面有个小例子:

public function username_unique(Validate $data, $field)
{
	// 确保 username 是唯一的
	...
}

_filters

protected $_filters = array
(
	TRUE       => array('trim' => array()),
	'username' => array('stripslashes' => array()),
);

TRUE 值代表 trim 过滤器应用到所有字段。而 username 字段则在校验前使用 stripslashes 过滤。那些传递空值数组用于提供可选的额外参数到校验方法中使用。

检测对象是否通过校验

使用 [ORM::check] 检测当前对象是否通过校验:

// 设置完对象的值,接下来检测是否通过校验
if ($user->values($_POST)->check())
{
	$user->save();
}

你也可是使用 validate() 方法直接访问模型的校验对象:

// 手动添加额外的过滤器
$user->validate()->filter('username', 'trim');