【问题标题】:Laravel Eloquent - Loading query scopes eagerlyLaravel Eloquent - 急切地加载查询范围
【发布时间】:2016-08-17 04:11:52
【问题描述】:

我有一个数据结构,我需要对象在其中了解加载所需的依赖关系。

我能做什么

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

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');
}

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

我需要做什么

目前在我的项目中不希望静态定义每个对象加载的范围。我需要能够加载票证,票证会加载它的所有关系,而这些关系中的每一个都会加载它们的所有关系。

我能想到的唯一方法是找到某种方法为类上的每个关系急切地加载查询范围。类似的东西

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

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

【问题讨论】:

    标签: php laravel eloquent eager-loading relationships


    【解决方案1】:

    也许你可以试试这样的:

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

    好的,这是一个想法,如何实施?例如,如果您有一些与 User 模型相关的方法,例如“posts”、“roles”等,则将所有相关方法(建立关系的方法)保存在单独的 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);
    

    这更加动态,无需提及相关方法,并且每当您在 trait 中添加新的关系方法时,它也会被加载。

    【讨论】:

    • 感谢您的意见。据我所知,这个解决方案仍然存在与我目前相同的问题。我不能将那些 withAll() 范围链接到下一个对象中。例如,我需要 notes()、events() 和 tags() 来使用它们自己的 withAll() 查询范围进行加载。
    • 我知道了,这只是一个示例,说明您可以如何为您拥有的每个模型做同样的事情。因此,您可能需要为每个模型创建withAll
    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 2017-10-09
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2014-05-21
    • 2018-03-29
    • 2013-06-10
    相关资源
    最近更新 更多