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

299 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ORM {#top}
Kohana 3.0 包含一个强劲的 ORM 扩展,作用于记录模式,数据库内省来确定模型的列表。
ORM 扩展默认包含在 Kohana 3.0 之中,但是如要使用它则需要先开启它。修改 `application/bootstrap.php` 文件中的 [Kohana::modules] 方法并加载 ORM 扩展:
Kohana::modules(array(
...
'orm' => MODPATH.'orm',
...
));
## 配置 {#configuration}
通过一些配置 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();
#### 使用 `Updated` 和 `Created` 列
`_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](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_id``student_id`。在定义关系时,使用 `foreign_key``far_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');