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

299 lines
10 KiB
Markdown
Raw Normal View History

2010-08-21 04:43:03 +00:00
# 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');