如何解决带有子查询和 foreach 的 Laravel 查询
a) 所有歌曲 b) 按标题或文字分类的歌曲 c) 标签歌曲
两个补充:
作为管理员的用户可以看到未经验证、被禁和过时的歌曲,作为艺术家的用户也可以看到未经证实或被禁的歌曲,但只能看到他自己的歌曲。
累了好几天了,'哪里哪里,哪个在循环中...'是一种折磨xD
歌曲模型:
class Song extends Model
{
use HasFactory,Likable;
public function artist()
{
return $this->belongsTo(Artist::class,'artist_id');
}
public function tags()
{
return $this->belongsToMany(Tag::class)->withTimestamps();
}
public function scopeByUser()
{
$user = current_user();
if ($user->hasRole('admin')) {
dd("x");
return $this;
} elseif (isset($user->artist)) {
return $this->where([
'isverified' => true,'isOutOfDate' => false,'isBanned' => false
])->orWhere(function () use ($user) {
foreach ($user->artist as $artist) {
$this->where([
'artist_id',$artist->id,'isBanned' => false
]);
}
});
} else
return $this->where([
'isverified' => true,'isBanned' => false
]);
}
}
歌曲控制器:
public function index(Request $request)
{
if (request('tag')) {
$songs = Song::query()
->whereHas('tags',function ($query) {
$tag = request('tag');
$query->where('name',$tag);
})
->ByUser()
->withLikes()
->get();
} elseif ($request) {
$search = $request->input('search');
$songs = Song::query()
->where('title','LIKE',"%{$search}%")->orWhere('text',"%{$search}%")
->ByUser()
->withLikes()
->get();
} else {
$songs = Song::latest()
->ByUser()
->withLikes()
->get();
}
return view('welcome',compact('songs'));
}
解决方法
我喜欢 Laravel Eloquent 的一件事是 when() 方法。
我知道链接在集合中,但它适用于查询。 因此,让我们检查您的查询并将其设置为可以进行逻辑测试和更改的查询。
有一个未经测试的代码,其唯一目的是向您展示您可以实现的目标。
$user = User::with('roles')->with('artists')->find(Auth::user()->id);
$songs = Song::when($request('tag'),function($query) use($request) {
$query->whereHas('tags',function($query2) use($request('tag')) {
$query2->where('name',$request('tag'));
});
})->when($request('search'),function($query) use($request) {
$query->where('title','LIKE',"%{$request('search)}%")->orWhere('text',"%{$request('search)}%");
})->when(!isset($request('search')) && !isset($request('tags')),function($query) {
$query->latest();
})->when(true,function($query) use($user) {//setting when to true let you do more complexe logical test
if ($user->hasRole('admin')) {
//Nothing to do...
} else if (isset($user->artist)) {
$query->where([
'isVerified' => true,'isOutOfDate' => false,'isBanned' => false
])->orWhere(function ($query2) use ($user) {
foreach ($user->artist as $artist) {
$query2->where([//probably change this to orWhere. You can also get the array of artist id and use whereIn('id',$arrayOfId)->where(['isOutOfDate' => false,'isBanned' => false]);
'artist_id',$artist->id,'isBanned' => false
]);
}
});
} else {
$query->where([
'isVerified' => true,'isBanned' => false
]);
}
})->ByUser()
->withLikes()
->get();
所以,回到你真正问的问题上来......使用范围......当你进行复杂的逻辑测试时,我不鼓励使用范围。为什么???仅仅因为看起来您的范围正在检索用户,并且我假设此方法至少向数据库发出一个请求...因此,这会导致 N+1 问题。
Scope 适用于简单的任务。一个范围内的 DB 请求将为每个模型执行请求。避免这种情况。
如果使用得当,when() 方法将帮助您构建复杂的查询,从而生成单个数据库查询。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。