Laravel 约束嵌套的第三级关系
我正在使用渴望加载构建一个api,这样我就可以简单地返回用户模型及其深层关系,并将其自动转换为json。这是设置Laravel 约束嵌套的第三级关系,laravel,laravel-5,eloquent,laravel-eloquent,laravel-5.5,Laravel,Laravel 5,Eloquent,Laravel Eloquent,Laravel 5.5,我正在使用渴望加载构建一个api,这样我就可以简单地返回用户模型及其深层关系,并将其自动转换为json。这是设置 users id .. clients id .. user_clients id user_id client_id .. campaigns id .. client_campaigns id client_id campaign_id .. campaign
users
id
..
clients
id
..
user_clients
id
user_id
client_id
..
campaigns
id
..
client_campaigns
id
client_id
campaign_id
..
campaign_activities
id
campaign_id
..
client_campaign_activity_templates
id
campaign_activity_id
client_id *(templates are unique per client)*
..
我已经建立了模型之间的关系
User
public function clients() {
return $this->belongsToMany('App\Client','user_clients');
}
Client
public function campaigns() {
return $this->belongsToMany('App\Campaign','client_campaigns');
}
Campaign
public function activities() {
return $this->hasMany('App\CampaignActivity');
}
CampaignActivity
public function templates() {
return $this->hasMany('App\ClientCampaignActivityTemplate')
}
我有一个简单的api端点来提供用户对象的JSON,包括使用渴望加载的深层关系
public function getLoggedInUser(Request $request) {
return \App\User::with('clients.campaigns.activities.templates')->find($request->user()->id);
}
通过使用postman进行测试,我可以获得用户,包括其深层次的关系
{
"user": {
"id": 1,
"name": "user1",
"clients": [
{
"id": 1,
"name": "client1",
"campaigns": [
{
"id": 1,
"name": "campaign1",
"activities": [
{
"id": 1,
"name": "activity1",
"templates": [
{
"id": 1,
"name": "template1 for client1",
"client_id": 1,
"body": "this is a template.",
}, {
"id": 2,
"name": "template1 for client2",
"client_id": 2,
"body": "This is a template for client2"
}
]
}, {
"id": 2,
"name": "activity2",
"templates": []
}, {
"id": 3,
"name": "activity3",
"templates": []
}
]
}
]
}
]
}
}
但是,在用户->客户->活动->活动->模板
级别,它将列出该活动的所有模板。根据上面模型之间的关系代码,我知道它的行为应该是这样的
因此,问题是如何筛选模板以同时筛选活动id和客户id?
我一直在试验如何过滤模板,以便只列出该活动以及该客户机的模板。我有一个有效的解决方案,但它是N+1,如果可能的话,我更喜欢雄辩的方法。我一直在用其他的问题、答案和评论来寻找一个非常相似的问题,但我运气不好,因此我发布了这篇文章,寻求你们的想法。谢谢你我想你需要的是
未测试,但只需要一个附加查询
我要做的是:为您的即时加载定义一个约束,即仅显示那些具有与用户相关的客户端id列表(
pull
)中的client\u id
的模板。尝试使用闭包过滤相关模型:
$users = App\User::with([
'clients' => function ($query) {
$query->where('id', $id);
},
'clients.campaigns' => function ($query) {
$query->where('id', $id);
}
])->get();
这是我的工作解决方案,但如果你们有更好的方法,我仍然感兴趣 在
activity
模型中,我添加了一个公共属性client\u id
,并将关系代码修改为
CampaignActivity
public $client_id = 0
public function templates() {
return $this->hasMany('App\ClientCampaignActivityTemplate')->where('client_id', $this->client_id);
}
在我的控制器上,将急切加载限制为仅限于活动(实际上,在这种情况下,使用急切加载[9]执行的SQL比仅使用迭代[7]执行的SQL更多,而且急切加载也不再有意义,因为我们正在迭代lol)
你可能想解释一下,而不是仅仅发布代码,或者冒着被删除的风险。谢谢matthias,我想我需要进一步澄清我的问题。但是你的代码所发生的事情是,它通过检查模板是否属于客户机,即属于用户,基本上缩小了模板的范围。因此,如果user1拥有client1和client2,那么activity1将在其模板下列出client1的
template1和client2的template1。我开始认为急切地将其加载到模板级别并不是解决我的问题的正确方法,因为每个客户端似乎都需要迭代模板才能获得结果。client2的模板1
不应包含在activity1的模板下client1
下,但是应该在activity1的模板中client2
:)我希望它能提供更多的图片
CampaignActivity
public $client_id = 0
public function templates() {
return $this->hasMany('App\ClientCampaignActivityTemplate')->where('client_id', $this->client_id);
}
public function getLoggedInUser(Request $request) {
foreach ($user->clients as $client)
foreach( $client->campaigns as $campaign)
foreach ($campaign->activities as $activity) {
$activity->client_id = $client->id;
$activity->templates; //to load the values
}
return $user;
}