Eloquent关联模型进阶技巧
如何修改父级 updated_at
如果我们想更新一条数据同时更新它父级关联的 updated_at 字段 (例如:我们添加一条文章评论,想同时更新文章的 articles.updated_at
),只需要在子模型中使用 $touches = ['article']
; 属性。
class Comment extends Model { protected $touches = ['article']; }
使用 withCount () 统计子关联记录数
如果我们有 hasMany() 的关联,并且我们想统计子关联记录的条数,不要写一个特殊的查询。
例如,如果我们的用户模型上有文章和评论,使用 withCount()
。
public function index() { $users = User::withCount(['articles', 'comments'])->get(); return view('users', compact('users')); }
同时,在 Blade 文件中,我们可以通过使用 {relationship}_count
属性获得这些数量:
@foreach ($users as $user) <tr> <td>{{ $user->name }}</td> <td class="text-center">{{ $user->articles_count }}</td> <td class="text-center">{{ $user->comments_count }}</td> </tr> @endforeach
还可以按照这些统计字段进行排序:
User::withCount('comments')->orderBy('comments_count', 'desc')->get();
在关联关系中过滤查询
假如我们想加载关联关系的数据,同时需要指定一些限制或者排序的闭包函数。
例如,我们想获取人口最多的前 5 个国家信息,可以按照如下方式实现:
$countries = Country::with(['contries' => function($query) { $query->orderBy('population', 'desc'); $query->take(5); }])->get();
动态预加载相关模型
我们不仅可以实现对关联模型的实时预加载,还可以根据情况动态设置某些关联关系,需要在模型初始化方法中处理:
class HobbyTag extends Model { protected $with = ['hobby']; public function __construct() { parent::__construct(); $this->with = ['hobby']; if (user()->check()) { $this->with[] = 'user'; } } }
使用 hasMany 代替 belongsTo
在关联关系中,如果创建子关系的记录中需要用到父关系的 ID
这种情况下使用 hasMany 比使用 belongsTo 更简洁。
比如:
如果 Post -> belongsTo(User)
, 并且 User -> hasMany(Post)
Post::create([ 'user_id' => auth()->id(), 'title' => request()->input('title'), 'post_text' => request()->input('post_text'), ]);
可以这样创建:
auth()->user()->posts()->create([ 'title' => request()->input('title'), 'post_text' => request()->input('post_text'), ]);
自定义 pivot 属性名称
如果我们想要重命名「pivot」并用其他的什么方式来调用关系,我们可以在关系声明中使用 ->as('name')
来为关系取名。
模型 Model:
public function podcasts() { return $this->belongsToMany('App\Podcast') ->as('subscription') ->withTimestamps(); }
控制器 Controller:
$podcasts = $user->podcasts(); foreach ($podcasts as $podcast) { // instead of $podcast->pivot->created_at ... echo $podcast->subscription->created_at; }
一行代码更新归属关系
如果有一个 belongsTo() 关系,我们可以只用一条语句中更新 Elquent 关系:
// if Project -> belongsTo(User::class) $project->user->update(['email' => 'wzy@qq.com']);