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 协议》,转载必须注明作者和本文链接
Night gathers, and now my watch begins.
本帖由 Summer 于 7年前 加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 3

这个新功能好像没什么鸟用,感觉更复杂了

7年前 评论

666 技能get到了,但是效果就是省了个中括号

6年前 评论

@anniversary 其实我觉得最主要的作用是去掉了一些重复代码

6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!