Laravel Eloquent 关系也可以使用宏啦
在 Eloquent ORM 中,如果想从一对多关系中取出一个特定值,可以通过添加一个附带特定子句的 hasOne
关系来实现。举个栗子,用户的最后一次登录记录:
class User
{
public function logins()
{
return $this->hasMany(Login::class);
}
public function lastLogin()
{
return $this->hasOne(Login::class)->latest();
}
}
看起来似乎已经很完美,除了 User 和 Login 的关系被定义了两次。在本来就容易变得琐碎的关系定义代码中,又增加了一些重复的味道。如果遇到更复杂的情况,比如取出用户的一些特定文章:点赞最多的文章、评论最多的文章、转发最多的文章、最后一次发布的文章等,重复就会在代码中蔓延开来。
对于追求优雅的 Laravel 程序员来说这怎么能忍,于是 v5.4.8 版本中合并了一个新特性:可以为 Eloquent 关系定义宏。
你只需在 AppServiceProvider
中添加如下代码:
use Illuminate\Database\Eloquent\Relations\HasOne;
//...
public function boot()
{
HasMany::macro('toHasOne', function() {
return new HasOne(
$this->query,
$this->parent,
$this->foreignKey,
$this->localKey
);
});
}
刚刚的例子可以改进为:
public function logins()
{
// 无论你需要多少个特定的一对一关系,Login 都只出现这一次
return $this->hasMany(Login::class);
}
public function lastLogin()
{
return $this->logins()->latest()->toHasOne();
}
然后我们这么用:
$user = App\User::find(1);
$user->logins()->first()->id; // 1
$user->logins()->count(); // 2
$logins = $user->lastLogin->id; // 2
是不是神清气爽了许多?
翻译 https://laravel-news.com/relationship-macr... 的时候,感觉文章说的不是很清楚,就扩充了一下。
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由 Summer
于 8年前 加精
这个新功能好像没什么鸟用,感觉更复杂了
666 技能get到了,但是效果就是省了个中括号
@anniversary 其实我觉得最主要的作用是去掉了一些重复代码