10 KiB
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();
使用 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
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');