0

我有一个名为 Laravel Eloquent ModelEmailList和一个名为Subscriber. 我在 EmailList 上定义了以下 hasMany 关系。

    public function subscribers() {
        return $this->hasMany(Subscriber::class);
    }

这种关系运作良好。

我现在想对where()父母应用一个条件where(),对孩子应用一个条件。

例如,我有两个EmailLists,一个属性id和一个名为listname(“List A”和“List B”)的属性。我的模型有Subscriber四个相关属性:idname和。emailemail_list_id

问题:我想从某个列表中获取所有订阅者,例如“列表 A”,并使用$query(Livewire 的搜索功能)过滤订阅者

为了做到这一点,我想出了以下代码:

EmailList::where('listname', $listname)->first()
                                    ->subscribers()
                                    ->where('name', 'LIKE', '%'.$this->search.'%')
                                    ->orWhere('email', 'LIKE', '%'.$this->search.'%')
                                    ->paginate(50) //or get(), if you like

此代码部分有效,因为订阅者确实被过滤了,但电子邮件列表没有。换句话说,我只是搜索了所有订阅者,而不是特定列表中的订阅者。

经过大量搜索后,我发现我可能应该使用 a whereHas(),但是当我尝试这样做时,它只给了我 EmailLists 而不是订阅者。

如果有人可以帮我过滤这个,那就太好了。对于经验丰富的开发人员来说,这可能是小菜一碟,但它对我有很大帮助!

更新: 在看到 EricLandheer 的答案后,我意识到(当然)我也有 EmailList id。也许这使它更简单一些,这样您就可以使用 find() 而不是 where()->first() 子句。(我使用 first() 因为 'listname' 是唯一的,我只想要一个实例。对吗?)

4

1 回答 1

1

目前,您的代码仅返回第一个EmailList. 你是故意的,还是你只想要第一个EmailList有 的$listname

这是一个使用带有约束的急切加载的解决方案,该约束通过回调覆盖subscribers关系。结果应该是全部EmailLists$listname搜索匹配的订阅者。

EmailList::where('listname', $listname)
    ->with('subscribers', function($query) {
        return $query->where('name', 'LIKE', '%'.$this->search.'%')
            ->orWhere('email', 'LIKE', '%'.$this->search.'%')
    })->get();

关于问题更新

确实,使用 Listname 很好。如果它是唯一的,没问题。您可以find()与 ID 一起使用,如果您想EmailList在稍后阶段更改名称,则更可取。

也许更优雅/可读的解决方案是:

$emailList = EmailList::firstWhere('listname', $listname);

$emailList->subscribers = $emailList->subscribers()
    ->where('name', 'LIKE', '%'.$this->search.'%')
    ->orWhere('email', 'LIKE', '%'.$this->search.'%')
    ->get();

如果您在更多地方使用它,您可以将搜索重构为模型/服务:

// EmailList model

public function subscribers() 
{
    return $this->hasMany(Subscriber::class);
}

public function searchSubscribers(string $search): Collection 
{
    return $this->subscribers()
        ->where('name', 'LIKE', '%'.$this->search.'%')
        ->orWhere('email', 'LIKE', '%'.$this->search.'%')
        ->get();
}

最终代码

$emailList = EmailList::firstWhere('listname', $listname);

$emailList->subscribers = $emailList->searchSubscribers($this->search);
于 2021-07-09T16:40:51.537 回答