Eloquent ORM
简介
Laravel 自带的 Eloquent ORM 为您的数据库提供了一个优雅的、简单的 ActiveRecord 实现。每一个数据库的表有一个对应的 "Model" 用来与这张表交互。
在开始之前,确认已在 app/config/database.php
文件中配置好数据库连接。
基本用法
首先,创建一个 Eloquent 模型。模型通常在 app/models
目录,但是您可以自由地把它们放在任何地方,只要它能根据您的 composer.json
文件自动加载。
定义一个 Eloquent 模型
class User extends Eloquent {}
注意我们并没有告诉 Eloquent 我们为 User
模型使用了哪一张表。类名的小写、复数的形式将作为表名,除非它被显式地指定。所以,在这种情况下,Eloquent 将假设 User
模型在 users
表中保存记录。您可以在模型中定义一个 table
属性来指定一个自定义的表名:
class User extends Eloquent {
protected $table = 'my_users';
}
Eloquent 将假设每张表有一个名 为 id
的主键。您可以定义 primaryKey
属性来覆盖这个约定。同样,您可以定义一个 connection
属性来覆盖在使用这个模型时所用的数据库连接。
一旦模型被定义,您可以开始在表中检索和创建记录。注意在默认情况下您将需要在表中定义 updated_at
和 created_at
字段。如果您不希望这些列被自动维护,在模型中设置 $timestamps
属性为 false
。
获取所有记录
$users = User::all();
根据主键获取一条记录
$user = User::find(1);
var_dump($user->name);
所有在 [查询构建器] 中适用的函数在 Eloquent 模型的查询中同样适用。
根据主键获取一条记录或者抛出一个异常
有时您可能希望当记录没有被找到时抛出一个异常,允许您使用 App::error
处理器捕捉这些异常并显示404页面。
$model = User::findOrFail(1);
$model = User::where('votes', '>', 100)->firstOrFail();
注册错误处理器,请监听 ModelNotFoundException
:
use Illuminate\Database\Eloquent\ModelNotFoundException;
App::error(function(ModelNotFoundException $e)
{
return Response::make('Not Found', 404);
});
使用 Eloquent 模型查询
$users = User::where('votes', '>', 100)->take(10)->get();
foreach ($users as $user)
{
var_dump($user->name);
}
当然,您也可以使用查询构建器的统计函数。
Eloquent 统计
$count = User::where('votes', '>', 100)->count();
如果您无法通过通过连贯的接口产生查询,可以使用 whereRaw
:
$users = User::whereRaw('age > ? and votes = 100', array(25))->get();
指定查询的数据库连接
您可能需要在运行一个 Eloquent 查询的时候指定数据库连接,只需要使用 on
函数:
$user = User::on('connection-name')->find(1);
集体赋值
当创建一个新的模型,您可以传递属性的数组到模型的构造函数。这些属性将通过集体赋值分配给模型。这是很方便的,但把用户的输入盲目地传给模型可能是一个严重的安全问题。如果把用户输入盲目地传递给模型,用户可以自由地修改任何或者全部模型的属性。基于这个原因,默认情况下所有 Eloquent 模型将防止集体赋值。
首先,在模型中设置 fillable
或 guarded
属性。
fillable
属性指定哪些属性可以被集体赋值。这可以在类或接口层设置。
在模型中定义 Fillable 属性
class User extends Eloquent {
protected $fillable = array('first_name', 'last_name', 'email');
}
在这个例子中,只有三个被列出的属性可以被集体赋值。
fillable
的反义词是 guarded
,将做为一个黑名单而不是白名单:
在模型中定义 Guarded 属性
class User extends Eloquent {
protected $guarded = array('id', 'password');
}
在这个例子中,id
和 password
属性将不被允许集体赋值。所有其他属性将被允许集体赋值。您可以使用 guard 方法阻止所有属性被集体赋值:
阻止所有属性集体赋值
protected $guarded = array('*');
插入、更新、删除
为了从模型中向数据库中创建一个新的记录,简单地创建一个模型实例并调用 save
函数。
保存一个新的模型
$user = new User;
$user->name = 'John';
$user->save();
通常您的 Eloquent 模型将有自动递增的键。然而,如果您希望指定您自定义的键,在模型中设置 incrementing
属性为 false
。
您也可以使用 create
函数在一行代码中保存一个新的模型。被插入的模型实例将从函数中返回。但是,在您这样做之前,您需要在模型中指定 fillable
或者 guarded
属性,因为所有 Eloquent 模型默认阻止集体赋值。
在保存或创建一个使用自增ID的新模型之后,可以通过对象的 id
属性获取此自增ID:
$insertedId = $user->id;
在模型中设置 Guarded 属性
class User extends Eloquent {
protected $guarded = array('id', 'account_id');
}
使用模型的 Create 函数
$user = User::create(array('name' => 'John'));
为了更新一个模型,您可以检索它,改变一个属性,然后使用 save
函数:
更新一个检索到的模型
$user = User::find(1);
$user->email = 'john@foo.com';
$user->save();
有时您可能希望不仅保存模型,还有它的所有关系。为此,您可以使用 push
函数:
保存一个模型和关系
$user->push();
您也可以在一组模型上运行更新:
$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2));
删除一个模型,在实例中调用 delete
函数:
删除一个存在的模型
$user = User::find(1);
$user->delete();
根据主键删除一个模型
User::destroy(1);
User::destroy(array(1, 2, 3));
User::destroy(1, 2, 3);
当然,您可以在一组模型中运行删除查询:
$affectedRows = User::where('votes', '>', 100)->delete();
如果您希望简单的在一个模型中更新时间戳,可以使用 touch
函数:
只更新模型的时间戳
$user->touch();
软删除
当软删除一个模型,它并没有真的从数据库中删除。相反,一个 deleted_at
时间戳在记录中被设置。为一个模型开启软删除,在模型中指定 softDelete
属性:
class User extends Eloquent {
protected $softDelete = true;
}
为了在您的表中添加一个 deleted_at
字段,您可以在迁移中使用 softDeletes
函数:
$table->softDeletes();
现在,当您在一个模型中调用 delete
函数,deleted_at
字段将被设置为当前的时间戳。在使用软删除的模型中查询,被软删除的模型将不被包含进查询结果中。为了强制已删除的 模型出现在结果集中,在查询中使用 withTrashed
函数:
强制软删除的模型到结果集中
$users = User::withTrashed()->where('account_id', 1)->get();
如果您希望在结果集中只包含软删除的模型,您可以使用 onlyTrashed
函数:
$users = User::onlyTrashed()->where('account_id', 1)->get();
恢复一个已被软删除的记录,使用 restore
函数:
$user->restore();
您也可以在查询中使用 restore
函数:
User::withTrashed()->where('account_id', 1)->restore();
restore
函数也可以在关系中被使用:
$user->posts()->restore();
如果您希望从数据库中真正删除一个模型,您可以使用 forceDelete
函数:
$user->forceDelete();
forceDelete
函数也可以在关系中被使用:
$user->posts()->forceDelete();
检测一个给定的模型实例是否被软删除,可以使用 trashed
函数:
if ($user->trashed())
{
//
}
时间戳
默认情况下,Eloquent 在数据的表中自动地将维护 created_at
和 updated_at
字段。只需简单的添加这些 timestamp
字段到表中,Eloquent 将为您做剩余的工作。如果您不希望 Eloquent 维护这些字段,在模型中添加以下属性:
禁止自动时间戳
class User extends Eloquent {
protected $table = 'users';
public $timestamps = false;
}
如果您希望定制时间戳的格式,可以在模型中重写 getDateFormat
函数:
提供一个定制的时间戳格式
class User extends Eloquent {
protected function getDateFormat()
{
return 'U';
}
}
查询范围
范围允许您容易在模型中重用查询逻辑。定义一个范围,简单的用 scope
为模型添加前缀:
定义一个查询范围
class User extends Eloquent {
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
public function scopeWomen($query)
{
return $query->whereGender('W');
}
}
使用一个查询范围
$users = User::popular()->women()->orderBy('created_at')->get();
动态范围
有时您可能希望定义一个接受参数的范围。只需要添加您的参数到您的范围函数:
class User extends Eloquent {
public function scopeOfType($query, $type)
{
return $query->whereType($type);
}
}
然后在范围函数调用中传递参数:
$users = User::ofType('member')->get();
关系
当然,您的数据库可能是彼此相关的。比如,一篇博客文章可能有许多评论,或者一个订单与下订单的用户相关。Eloquent 使得管理和处理这些关系变得简单。Laravel 提供了四种类型的关系:
一对一
一个一对一关系是一种非常基础的关系。比如,一个 User
模型可以有一个 Phone`。我们可以在 Eloquent 中定义这个关系:
定义一个一对一关系
class User extends Eloquent {
public function phone()
{
return $this->hasOne('Phone');
}
}
传递给 hasOne
函数的第一个参数是相关模型的名字。一旦这个关系被定义,我们可以使用 Eloquent 的 [动态属性] 获取它:
$phone = User::find(1)->phone;
这条语句所产生的 SQL 语句如下:
select * from users where id = 1
select * from phones where user_id = 1
注意 Eloquent 假设关系的外键基于模型的名字。在这个例子中假设 Phone
模型使用一个 user_id
外键。如果您希望覆盖这个惯例,您可以为传递 hasOne
函数传递第二个参数:
return $this->hasOne('Phone', 'custom_key');
在 Phone
模型定义逆向关系,我们使用 belongsTo
函数:
定义一个逆向关系
class Phone extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
在上面的例子中,Eloquent 将在 phones
表中寻找 user_id
字段。如果您想定义一个不同的外键字段,您可以通过 belongsTo
函数的第二个参数传递它:
class Phone extends Eloquent {
public function user()
{
return $this->belongsTo('User', 'custom_key');
}
}
一对多
一个一对多关系的例子是一篇博客文章有许多评论。我们可以像这样定义关系模型:
class Post extends Eloquent {
public function comments()
{
return $this->hasMany('Comment');
}
}
现在我们可以通过 动态属性 访问文章的评论:
$comments = Post::find(1)->comments;
如果您需要添加进一步的约束检索哪些评论,我们可以调用 comments
函数连接链式条件:
$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first();
再次,如果您想覆盖默认的外键,可以给 hasMany
函数传递第二个参数:
return $this->hasMany('Comment', 'custom_key');
在 Comment
模型中定义逆向关系,我们使用 belongsTo
函数:
定义逆向关系
class Comment extends Eloquent {
public function post()
{
return $this->belongsTo('Post');
}
}