菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
1723
3

Laravel Eloquent 关系也可以使用宏啦

原创
05/13 14:22
阅读数 3119

在 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... 的时候,感觉文章说的不是很清楚,就扩充了一下。

发表评论

0/200
1723 点赞
3 评论
收藏
为你推荐 换一批