您好,欢迎访问一九零五行业门户网

Laravel Eloquent ORM整理

介绍 laravel 的 eloquent orm 提供了漂亮、简洁的 activerecord 实现来和数据库的互动。 每个数据库表会和一个对应的「模型」互动。
在开始之前,记得把 config/database.php 里的数据库连接配置好。
基本用法 我们先从建立一个 eloquent 模型开始。模型通常放在 app 目录下,但是您可以将它们放在任何地方,只要能通过 composer.json 自动载入。所有的 eloquent 模型都继承于 illuminate\database\eloquent\model .
例如我放在app/models下,则在composer.json中的配置如下: autoload-dev: { classmap: [tests/testcase.php, app/models]},
1. 创建[模型] 手动创建 在app/models下新建文件logo.php
? and votes = 100', [25])->get();
软删除 通过软删除方式删除了一个模型后,模型中的数据并不是真的从数据库被移除。而是会设定 deleted_at时间戳。要让模型使用软删除功能,只要在模型类里加入 softdeletingtrait 即可:
use illuminate\database\eloquent\softdeletes;class user extends model { use softdeletes; protected $dates = ['deleted_at'];}
要加入 deleted_at 字段到数据库表,可以在迁移文件里使用 softdeletes 方法:
$table->softdeletes();
现在当您使用模型调用 delete 方法时, deleted_at字段会被更新成现在的时间戳。在查询使用软删除功能的模型时,被「删除」的模型数据不会出现在查询结果里。
普通查询方法只能查询到deleted_at为null的数据,也就是未被删除/有效的数据。要强制让已被软删除的模型数据出现在查询结果里,在查询时使用 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();
如果想要真的从模型数据库删除,使用 forcedelete 方法: $user->forcedelete();
要确认模型是否被软删除了,可以使用 trashed 方法: if ($user->trashed()){ //}
范围查询 定义范围查询 范围查询可以让您轻松的重复利用模型的查询逻辑。要设定范围查询,只要定义有 scope 前缀的模型方法:
class user extends model { 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 model { public function scopeoftype($query, $type) { return $query->wheretype($type); }}
然后把参数值传到范围查询方法调用里:
$users = user::oftype('member')->get();
3. 关联 一对一 定义一对一关联 一对一关联是很基本的关联。例如一个 user 模型会对应到一个 phone 。 在 eloquent 里可以像下面这样定义关联:
class user extends model { public function phone() { return $this->hasone('app\phone'); }}
传到 hasone 方法里的第一个参数是关联模型的类名称。定义好关联之后,就可以使用 eloquent 的动态属性取得关联对象:
$phone = user::find(1)->phone;
sql 会执行如下语句:
select * from users where id = 1select * from phones where user_id = 1
注意, eloquent 假设对应的关联模型数据库表里,外键名称是基于模型名称。在这个例子里,默认 phone 模型数据库表会以 user_id 作为外键。如果想要更改这个默认,可以传入第二个参数到 hasone 方法里。更进一步,您可以传入第三个参数,指定关联的外键要对应到本身的哪个字段: return $this->hasone('app\phone', 'foreign_key');return $this->hasone('app\phone', 'foreign_key', 'local_key');
定义相对的关联 要在 phone 模型里定义相对的关联,可以使用 belongsto 方法:
class phone extends model { public function user() { return $this->belongsto('app\user'); }}
在上面的例子里, eloquent 默认会使用 phones 数据库表的 user_id 字段查询关联。如果想要自己指定外键字段,可以在 belongsto 方法里传入第二个参数:
class phone extends model { public function user() { return $this->belongsto('app\user', 'local_key'); }}
除此之外,也可以传入第三个参数指定要参照上层数据库表的哪个字段:
class phone extends model { public function user() { return $this->belongsto('app\user', 'local_key', 'parent_key'); }}
一对多 定义一对多关联 一对多关联的例子如,一篇 blog 文章可能「有很多」评论。可以像这样定义关联:
class post extends model { public function comments() { return $this->hasmany('app\comment'); }}
现在可以经由动态属性取得文章的评论:
$comments = post::find(1)->comments;
如果需要增加更多条件限制,可以在调用 comments 方法后面通过链式查询条件方法:
$comments = post::find(1)->comments()->where('title', '=', 'foo')->first();
同样的,您可以传入第二个参数到 hasmany 方法更改默认的外键名称。以及,如同 hasone 关联,可以指定本身的对应字段:
return $this->hasmany('app\comment', 'foreign_key');return $this->hasmany('app\comment', 'foreign_key', 'local_key');
定义相对的关联 要在 comment 模型定义相对应的关联,可使用 belongsto 方法:
class comment extends model { public function post() { return $this->belongsto('app\post'); }}
多对多 定义多对多关联 多对多关联更为复杂。这种关联的例子如,一个用户( user )可能用有很多身份( role ),而一种身份可能很多用户都有。例如很多用户都是「管理者」。多对多关联需要用到三个数据库表: users , roles ,和 role_user 。 role_user 枢纽表命名是以相关联的两个模型数据库表,依照字母顺序命名,枢纽表里面应该要有 user_id 和 role_id 字段。
可以使用 belongstomany 方法定义多对多关系:
class user extends model { public function roles() { return $this->belongstomany('app\role'); }}class role extends model { public function users() { return $this->belongstomany('app\user'); }}
现在我们可以从 user 模型取得 roles:
$roles = user::find(1)->roles;
如果不想使用默认的枢纽数据库表命名方式,可以传递数据库表名称作为 belongstomany 方法的第二个参数:
return $this->belongstomany('app\role', 'user_roles');
也可以更改默认的关联字段名称:
return $this->belongstomany('app\role', 'user_roles', 'user_id', 'foo_id');
has many through 远层一对多关联 「远层一对多关联」提供了方便简短的方法,可以经由多层间的关联取得远层的关联。例如,一个 country 模型可能通过 users 关联到很多 posts 模型。 数据库表间的关系可能看起来如下:
countries id - integer name - stringusers id - integer country_id - integer name - stringposts id - integer user_id - integer title - string
虽然 posts 数据库表本身没有 country_id 字段,但 hasmanythrough 方法让我们可以使用 $country->posts 取得 country 的 posts。我们可以定义以下关联:
class country extends model { public function posts() { return $this->hasmanythrough('app\post', 'app\user'); }}
如果想要手动指定关联的字段名称,可以传入第三和第四个参数到方法里:
class country extends model { public function posts() { return $this->hasmanythrough('app\post', 'app\user', 'country_id', 'user_id'); }}
关联查询 根据关联条件查询 在取得模型数据时,您可能想要以关联模型作为查询限制。例如,您可能想要取得所有「至少有一篇评论」的blog 文章。可以使用 has 方法达成目的:
$posts = post::has('comments')->get();
也可以指定运算符和数量:
$posts = post::has('comments', '>=', 3)->get();
也可以使用”点号”的形式来获取嵌套的 has 声明:
$posts = post::has('comments.votes')->get();
如果想要更进阶的用法,可以使用 wherehas 和 orwherehas 方法,在 has 查询里设置 “where” 条件 :
$posts = post::wherehas('comments', function($q){ $q->where('content', 'like', 'foo%');})->get();
动态属性 eloquent 可以经由动态属性取得关联对象。 eloquent 会自动进行关联查询,而且会很聪明的知道应该要使用 get(用在一对多关联)或是 first (用在一对一关联)方法。可以经由和「关联方法名称相同」的动态属性取得对象。例如,如下面的模型对象 $phone:
class phone extends model { public function user() { return $this->belongsto('app\user'); }}$phone = phone::find(1);
您可以不用像下面这样打印用户的 email :echo $phone->user()->first()->email;
而可以简写如下:echo $phone->user->email;
若取得的是许多关联对象,会返回 illuminate\database\eloquent\collection 对象。 预载入 预载入是用来减少 n + 1 查询问题。例如,一个 book 模型数据会关联到一个 author 。关联会像下面这样定义:
class book extends model { public function author() { return $this->belongsto('app\author'); }}
现在考虑下面的代码:
foreach (book::all() as $book){ echo $book->author->name;}
上面的循环会执行一次查询取回所有数据库表上的书籍,然而每本书籍都会执行一次查询取得作者。所以若我们有 25 本书,就会进行 26次查询。
很幸运地,我们可以使用预载入大量减少查询次数。使用 with 方法指定想要预载入的关联对象:
foreach (book::with('author')->get() as $book) { echo $book->author->name;}
现在,上面的循环总共只会执行两次查询:
select * from booksselect * from authors where id in (1, 2, 3, 4, 5, ...)
使用预载入可以大大提高程序的性能。
当然,也可以同时载入多种关联:
$books = book::with('author', 'publisher')->get();
预载入条件限制 有时您可能想要预载入关联,同时也想要指定载入时的查询限制。下面有一个例子:
$users = user::with(['posts' => function($query) { $query->where('title', 'like', '%first%');}])->get();
上面的例子里,我们预载入了 user 的 posts 关联,并限制条件为 post 的 title 字段需包含 “first” 。
当然,预载入的闭合函数里不一定只能加上条件限制,也可以加上排序:
$users = user::with(['posts' => function($query) { $query->orderby('created_at', 'desc');}])->get();
新增关联模型 附加一个关联模型 您常常会需要加入新的关联模型。例如新增一个 comment 到 post 。除了手动设定模型的 post_id 外键,
也可以从上层的 post 模型新增关联的 comment :
$comment = new comment(['message' => 'a new comment.']);$post = post::find(1);$comment = $post->comments()->save($comment);
上面的例子里,新增的 comment 模型中 post_id 字段会被自动设定。
如果想要同时新增很多关联模型:
$comments = [ new comment(['message' => 'a new comment.']), new comment(['message' => 'another comment.']), new comment(['message' => 'the latest comment.'])];$post = post::find(1);$post->comments()->savemany($comments);
从属关联模型 ( belongs to ) 要更新 belongsto 关联时,可以使用 associate 方法。这个方法会设定子模型的外键:
$account = account::find(10);$user->account()->associate($account);$user->save();
新增多对多关联模型 ( many to many ) 您也可以新增多对多的关联模型。让我们继续使用 user 和 role 模型作为例子。我们可以使用 attach 方法简单地把 roles 附加给一个 user:
附加多对多模型 $user = user::find(1);$user->roles()->attach(1);
也可以传入要存在枢纽表中的属性数组:
$user->roles()->attach(1, ['expires' => $expires]);
当然,有 attach 方法就会有相反的 detach 方法:
$user->roles()->detach(1);
attach 和 detach 都可以接受id数组作为参数:
$user = user::find(1);$user->roles()->detach([1, 2, 3]);$user->roles()->attach([1 => ['attribute1' => 'value1'], 2, 3]);
使用 sync 方法同时附加一个以上多对多关联 您也可以使用 sync 方法附加关联模型。 sync 方法会把根据 id 数组把关联存到枢纽表。附加完关联后,枢纽表里的模型只会关联到 id 数组里的 id :
$user->roles()->sync([1, 2, 3]);
sync 时在枢纽表加入额外数据 也可以在把每个 id 加入枢纽表时,加入其他字段的数据:
$user->roles()->sync([1 => ['expires' => true]]);
有时您可能想要使用一个命令,在建立新模型数据的同时附加关联。可以使用 save 方法达成目的:
$role = new role(['name' => 'editor']);user::find(1)->roles()->save($role);
上面的例子里,新的 role 模型对象会在储存的同时关联到 user 模型。也可以传入属性数组把数据加到关联数据库表:
user::find(1)->roles()->save($role, ['expires' => $expires]);
其它类似信息

推荐信息