如何使用父枢轴值作为条件获得雄辩的关系

Posted

技术标签:

【中文标题】如何使用父枢轴值作为条件获得雄辩的关系【英文标题】:How to get eloquent relationship using parent pivot value as where condition 【发布时间】:2019-11-21 10:08:06 【问题描述】:

我试图在 Eloquent 中获得 hasMany 关系,但在 where 子句中使用父数据透视表的值。

例如

class Page

    public function modules()
    
        return $this->belongsToMany(Module::class)->withPivot('sun_id');
    


class Module

    public function settings()
    
        return $this->hasMany(ModuleSetting::class)
            ->where('sun_id', $this->pivot->sun_id);
    


$page = Page::with('modules.settings')->get();

“设置”功能中的$this->pivot-sun_id 显然不起作用。我怎样才能做到这一点?声明 $page 时是否需要编写原始 DB 语句,还是有更“雄辩”的方法?

谢谢

编辑

附上我的表格架构。

pages:表格是不言自明的。包含页面列表 模块:模块是页面元素。例如一段文本或一个日历 module_page:将模块绑定到页面的数据透视表 模块设置。一个页面可以有多个相同类型的模块。以两个日历为例。模块设置表定义 日历的设置,例如颜色,如果日历是 可下载等。

【问题讨论】:

你能分享更多关于相关关系和表格的信息吗?例如ModelSettingSetting 也许?我们或许可以给出正确的答案。可能你需要看看custom intermediat table models。 【参考方案1】:

我已经删除了之前的回复,因为我在这里复制了很多内容。我相信您可以使用自定义收集方法来实现您想要的特定于页面的结果,同时保持雄辩的风格响应并保持您的调用相当简单。这似乎对我有用。

不幸的是,我不相信严格按照雄辩的关系来做你所要求的事情是可能的,因为一旦你进入模块,就没有办法“返回”来获取页面 ID。

您会注意到有两种withModuleSettings() 方法,一种用于页面集合,另一种用于单个页面。

创建一个新文件:

App/PageCollection.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Collection;

class PageCollection extends Collection

    // this will load the module settings based on page id
    public function withModuleSettings()
    
        foreach ($this as $p => $page) 
            $this[$p]->withModuleSettings();
        

        return $this;
    

您的模型:

class Page extends Model

    // ... 

    public function modules()
    
        return $this->belongsToMany(Module::class)->withPivot('module_instance');
    

    // override the default collection instance with our own
    public function newCollection(array $models = [])
    
        return new PageCollection($models);
    

    // this will load the module settings based on page id
    public function withModuleSettings()
    
        // this page id
        $id = $this->id;

        foreach ($this->modules as $m => $module) 

            // get module instance from pivot
            $instance = $module->pivot->module_instance;

            // load relations
            $this->modules[$m]->load(['settings' => function($query) use ($id, $instance) 
                $query
                    ->where('module_settings.page_id',$id)
                    ->where('module_settings.module_instance',$instance)
                ;
            ]);
        

        return $this;
    


class Module extends Model

    // ...

    public function settings()
    
        return $this->hasManyThrough(
            ModuleSetting::class,
            ModulePage::class,
            'module_id',         // first key
            'module_instance',   // second key
            'id',                // local key
            'module_instance'    // second local key
        );
    


class ModulePage extends Model

    // define the table name since Laravel expects it to be 'module_pages'
    protected $table = 'module_page';


class ModuleSetting extends Model

    // ...


动作:

$pages = Page::with('modules')->get()->withModuleSettings();

也适用于单页:

$page = Page::with('modules')->first()->withModuleSettings();

【讨论】:

非常感谢您的帮助。它非常接近工作。唯一的问题是,module_settings 表中的module_instance 不一定是唯一的。它只是每页唯一的。例如,我可以在 page_id 1 上添加一个日历,它的 module_instance 为 1。然后我可以在 page_id 2 上添加相同的模块,它的模块实例也将为 1。这会导致两者上的模块设置正在返回的页面。我需要使 module_instance 唯一还是有办法只过滤掉一个页面的设置? 我认为您可能需要反过来做。请参阅我的编辑。我希望这会有所帮助。 那会很完美。你是一个传奇。我现在只需要查看您的两个示例并了解这些函数实际上在做什么。再次感谢您的帮助。 我决定最好确保所有 module_instance id 都是唯一的(出于此处未提及的原因),因此求助于您的第一个答案 - 这对我来说效果更好。但是,当我将两个相同类型的模块添加到一个页面时 - 即使具有唯一的 module_instance id,设置也包含来自两个实例的项目。现在我有了唯一的 module_instance id,有没有一种简单的方法可以防止这种情况发生? 这是一个演示问题的小提琴。我有一个页面和一个模块。该模块被添加到页面两次并给出了不同的设置,但输出显示了两个模块的设置。 implode.io/aDOCa9

以上是关于如何使用父枢轴值作为条件获得雄辩的关系的主要内容,如果未能解决你的问题,请参考以下文章

使用现有表模式上的数据透视表在雄辩模型中指定关系字段

如何在 Laravel 雄辩关系中添加多个条件

Laravel 通过属性获得雄辩的查询构建器关系

如何在快速排序中选择枢轴值?

laravel 雄辩的 where 子句与枢轴

如何在 laravel 雄辩的关系中使用 where 子句