Laravel Eloquent - 急切地加载查询范围

时间:2016-04-23 14:50:41

标签: php laravel eloquent eager-loading relationships

我有一个数据结构,我需要对象知道它们所需的加载依赖项。

我能做什么

目前,我可以这样做来加载第一层关系,这显然是一个非常基本的模型:

class Ticket {

    public function notes(){}
    public function events(){}
    public function tags(){}

    public function scopeWithAll($query)
    {
        $query->with('notes', 'events', 'tags');
    }

}

// Loads Ticket with all 3 relationships
$ticket = Ticket::withAll();

这很棒!问题是,我需要将此功能链接到3-5级依赖关系。 3个加载模型中的每一个都将拥有自己的n个关系。

我知道如果我指定所有关系名称,我可以通过急切加载来完成此操作,如下所示:

public function scopeWithAll($query)
{
    $query->with('notes.attachments', 'notes.colors', 'events', 'tags', 'tags.colors.', 'tags.users.email');
}

这也很有用。但我需要我的代码比这更聪明。

我需要做什么

在我的项目中,此时不可能静态定义每个对象加载的范围。我需要能够加载Ticket,并且Ticket加载它的所有关系,并且每个关系都会加载它们的所有关系。

我能想到的唯一方法就是找到一种方法来急切地为类中的每个关系加载查询范围。像

这样的东西
public function scopeWithAll($query)
{
    $query->with('notes.withAll()', 'events.withAll()', 'tags.withAll()');
}

目前是否有办法在Eloquent中执行此操作?

1 个答案:

答案 0 :(得分:0)

也许你可以尝试这样的事情:

User::withRelatives()->find(1);

好的,这是一个想法以及如何实现它?例如,如果您的User模型有一些相关的方法,例如'帖子','角色'然后将所有相关方法(建立关系的方法)保存在单独的trait中,例如:

trait UserRelatives {
    public function posts()
    {
        // ...
    }

    public function roles()
    {
        // ...
    }
}

现在,在User模型中,您可以创建一个scopeMethod,如withAll,在那里您可以尝试这样的事情:

public function scopeWithAll($query)
{
    // Get all the related methods defined in the trait
    $relatives = get_class_methods(UserRelatives::class);
    return $query->with($relatives);
}

所以,如果你做这样的事情:

$user = User::withAll()->find(1);

您可以加载所有相关模型。顺便说一句,get_class_methods(UserRelatives::class)会给你一个在该特征中定义的所有方法的数组,它们看起来像这样:

['posts', 'roles']

因此,User::withAll()将加载所有相关模型,然后运行query。因此,范围将执行以下操作:

$query->with(['posts', 'roles']);

嗯,这是一个抽象的想法,但希望你能得到它。如果你发现了更好的东西,请分享你的想法。

更新

根据您的模型和相关方法,这看起来像这样:

class Ticket {

    use TicketRelativesTrait;

    public function scopeWithAll($query)
    {
        $relatives = get_class_methods(TicketRelativesTrait::class);
        return $query->with($relatives);
    }
}

特点:

trait TicketRelativesTrait {
    public function notes(){}
    public function events(){}
    public function tags(){}
}


// Loads Ticket with all relationships
$ticket = Ticket::withAll()->find(1);

这更具动态性,无需提及相关方法,每当在特征中添加新的关系方法时,也会加载。