【问题标题】:Laravel build dynamic relationship EloquentLaravel 建立动态关系 Eloquent
【发布时间】:2022-01-24 21:24:40
【问题描述】:

我最近在概念上遇到了一些障碍。

我有一个名为“Clients”的表,其中客户有数字经理(digitalManagers、belongsToMany、Users 表到中间表)和常规经理(managers、belongsToMany、Users 表到中间表)。

客户表的关系摘录:

/**
 * Get the assigned users (managers) to this client
 * @return BelongsToMany
 */
public function managers(): BelongsToMany
{
    return $this->belongsToMany(
        User::class,
        ClientAssignment::class,
        'client_id',
        'user_id'
    );
}


/**
 * Get the assigned digital managers for this client
 * @return BelongsToMany
 */
public function digitalManagers(): BelongsToMany
{
    return $this->belongsToMany(
        User::class,
        'digital_managers',
        'client_id',
        'user_id'
    );
}

因此我可以通过Client::findOrFail(1)->digitalManagers()->get()轻松查询数字经理

最近,当名为 digital_merge_with_global 的设置为 true 时,我想添加功能以将常规经理与客户的数字经理合并。我想“动态地”执行此操作(我有我的理由),而不是每次添加/删除常规经理时都更新 digitalManagers->users 中间表。

我可以通过以下代码完成这个逻辑:

$client = $client->load('digitalManagers:id,first_name,last_name,email,avatar', 'managers:id,first_name,last_name,email,avatar');

$definedDigitalManagers = $allManagers = $client->digitalManagers;

if ($client->settings->get('digital_merge_with_global') == true) {
    $regularManagersToAdd = $client->managers;

    foreach ($regularManagersToAdd as $manager) {
        if (!$definedDigitalManagers->contains('id', $manager->id)) {
            $allManagers->add($manager);
        }
    }
}

但我想知道是否有一种方法可以将其定义为一种关系(封装相同的逻辑但作为某种类型的关系)来代替上述public function digitalManagers(),或者我是否只是要求太多Laravel 的。 我查看了docs,但有些概念有点超出我的想象。

理想情况下,我想运行 Client::findOrFail(1)->digitalManagers()->get() 并获取之前代码 sn-p 的输出。

【问题讨论】:

    标签: php mysql laravel relationship laravel-8


    【解决方案1】:

    我不知道你对运行Client::findOrFail(1)->digitalManagers()->get() 并获得输出有多严格,但是,extending collections 在我看来可以解决你的问题。因此,该句子将转换为Client::findOrFail(1)->get()->withAllManagers()。您将能够在您创建的宏中实现代码 sn-p 的逻辑。

    下面的 sn-p 显示了应该在服务提供者中定义的宏的定义。

    use Illuminate\Support\Collection;
    
    Collection::macro('withAllManagers', function () {
        foreach ($this as $client) {
            $client = $client->load('digitalManagers:id,first_name,last_name,email,avatar', 'managers:id,first_name,last_name,email,avatar');
    
            $definedDigitalManagers = $allManagers = $client->digitalManagers;
    
            if ($client->settings->get('digital_merge_with_global') == true) {
                $regularManagersToAdd = $client->managers;
    
                foreach ($regularManagersToAdd as $manager) {
                    if (!$definedDigitalManagers->contains('id', $manager->id)) {
                        $allManagers->add($manager);
                    }
                }
            }
    
            $client->allManagers = $allManagers;
        }
    
        return $this;
    });
    

    添加宏后,您将使用它作为Client::findOrFail(1)->get()->withAllManagers()。我认为它会解决您的问题,即使它可能不是在查询级别生成的。

    【讨论】:

    • 我不明白你所说的“你要运行多少严格”是什么意思......而且我知道如何修改关系并将项目添加到集合中(参见上面的代码 sn-p ),但修改集合并不能真正解决我的问题,因为集合是在数据库查询之后生成的。
    • 我刚刚更新了我的答案以澄清。没错,它不能在查询级别解决,但是我认为这种方式不会比查询级别复杂得多。
    猜你喜欢
    • 2021-02-06
    • 1970-01-01
    • 2019-03-05
    • 2019-01-21
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    相关资源
    最近更新 更多